Bạn có thể thay đổi những gì một symlink trỏ đến sau khi nó được tạo ra không?


122

Có bất kỳ hệ điều hành nào cung cấp một cơ chế (gọi hệ thống - không phải chương trình dòng lệnh) để thay đổi tên đường dẫn được tham chiếu bởi một liên kết tượng trưng (symlink) - ngoài việc hủy liên kết cái cũ và tạo một cái mới?

Tiêu chuẩn POSIX thì không. Solaris 10 thì không. MacOS X 10.5 (Leopard) thì không. (Tôi hoàn toàn có thể chắc chắn cả AIX và HP-UX đều không. Đánh giá từ danh sách các cuộc gọi hệ thống Linux này, Linux cũng không có cuộc gọi hệ thống như vậy.)

Có bất cứ điều gì không?

(Tôi đang mong đợi rằng câu trả lời là "Không".)


Vì việc chứng minh tiêu cực là khó, chúng ta hãy sắp xếp lại câu hỏi.

Nếu bạn biết rằng một số hệ điều hành (giống Unix) chưa được liệt kê không có lệnh gọi hệ thống để viết lại giá trị của một liên kết tượng trưng (chuỗi được trả về bởi readlink()) mà không xóa liên kết cũ và tạo một liên kết mới, vui lòng thêm nó - hoặc chúng - trong một câu trả lời


Có gì sai khi chỉ đơn giản là xem lại? Tại sao không chỉ đưa ra lnlệnh (hoặc API tương đương) ghi đè lên liên kết cũ? Bạn gặp vấn đề gì?
S.Lott

9
Hài hước - Tôi đang hỏi liệu có một cuộc gọi hệ thống để thực hiện công việc lập trình hay không và câu hỏi đang được đánh dấu 'thuộc về trang web khác'.
Jonathan Leffler

3
Hài hước- Hoàn toàn không rõ bạn đang tìm kiếm một cuộc gọi hệ thống và bạn chỉ cần chỉnh sửa câu hỏi để thêm chi tiết này. Vì vậy, làm thế nào bạn có thể mong đợi mọi người khấu trừ một cái gì đó trước khi bạn viết nó?
Pascal Thivent

2
@ S.Lott: Tôi đang viết một bài báo về các liên kết tượng trưng và bảo mật. Tại một thời điểm tôi đưa ra khẳng định "chủ sở hữu thực tế, nhóm, quyền trên chính liên kết tượng trưng là không quan trọng" và lý do là chủ sở hữu của liên kết tượng trưng chỉ có thể xóa nó và không thay đổi giá trị. Tôi đang kiểm tra hai lần rằng không có cách nào khác ngoài việc loại bỏ liên kết tượng trưng để đạt được hiệu quả của 'viết lại giá trị liên kết tượng trưng'. Tôi đang bỏ qua quyền truy cập trực tiếp vào đĩa thô và hack FS theo cách đó - nó đòi hỏi đặc quyền root và mối quan tâm của tôi là với người dùng không phải root, không phải với những gì root có thể làm.
Jonathan Leffler

4
@Pascal: Tôi xin lỗi - Tôi không nhận ra rằng tôi đã nói về các cuộc gọi hệ thống cho đến khi mọi người tiếp tục với những gì tôi dự định (rõ ràng khác với những gì tôi nói). Tôi xin lỗi vì đã đánh lừa; đó là vô ý.
Jonathan Leffler

Câu trả lời:


106

AFAIK, không, bạn không thể. Bạn phải loại bỏ nó và tạo lại nó. Trên thực tế, bạn có thể ghi đè lên một liên kết tượng trưng và do đó cập nhật tên đường dẫn được tham chiếu bởi nó:

$ ln -s .bashrc test
$ ls -al test
lrwxrwxrwx 1 pascal pascal 7 2009-09-23 17:12 test -> .bashrc
$ ln -s .profile test
ln: creating symbolic link `test': File exists
$ ln -s -f .profile test
$ ls -al test
lrwxrwxrwx 1 pascal pascal 8 2009-09-23 17:12 test -> .profile

EDIT : Như OP đã chỉ ra trong một bình luận, sử dụng --forcetùy chọn sẽ thực lnhiện cuộc gọi hệ thống unlink()trước đó symlink(). Dưới đây, đầu ra của stracehộp linux của tôi chứng minh điều đó:

$ strace -o /tmp/output.txt ln -s -f .bash_aliases test
$ grep -C3 ^unlink /tmp/output.txt 
lstat64("test", {st_mode=S_IFLNK|0777, st_size=7, ...}) = 0
stat64(".bash_aliases", {st_mode=S_IFREG|0644, st_size=2043, ...}) = 0
symlink(".bash_aliases", "test")        = -1 EEXIST (File exists)
unlink("test")                          = 0
symlink(".bash_aliases", "test")        = 0
close(0)                                = 0
close(1)                                = 0

Vì vậy, tôi đoán câu trả lời cuối cùng là "không".

EDIT : Phần sau đây được sao chép từ câu trả lời của Arto Bendiken trên unix.stackexchange.com, vào khoảng năm 2016.

Điều này thực sự có thể được thực hiện bằng nguyên tử rename(2), bằng cách trước tiên tạo liên kết tượng trưng mới dưới tên tạm thời và sau đó ghi đè lên liên kết tượng trưng cũ trong một lần. Như trang người đàn ông nói:

Nếu newpath đề cập đến một liên kết tượng trưng, ​​liên kết sẽ bị ghi đè.

Trong shell, bạn sẽ làm điều này mv -Tnhư sau:

$ mkdir a b
$ ln -s a z
$ ln -s b z.new
$ mv -T z.new z

Bạn có thể stracethực hiện lệnh cuối cùng để đảm bảo rằng nó thực sự được sử dụng rename(2)dưới mui xe:

$ strace mv -T z.new z
lstat64("z.new", {st_mode=S_IFLNK|0777, st_size=1, ...}) = 0
lstat64("z", {st_mode=S_IFLNK|0777, st_size=1, ...}) = 0
rename("z.new", "z")                    = 0

Lưu ý rằng ở trên, cả hai mv -Tstraceđều dành riêng cho Linux.

Trên FreeBSD, sử dụng mv -hluân phiên.

Lưu ý của biên tập viên: Đây là cách Capistrano đã thực hiện nó trong nhiều năm nay, kể từ ~ 2,15. Xem yêu cầu kéo này .


2
Không phải tùy chọn '-f' buộc 'ln' thực hiện các cuộc gọi hệ thống unlink () rồi symlink () sao?
Jonathan Leffler

1
Nó làm. Nhưng câu hỏi có thể được coi là "làm thế nào để tôi làm điều đó trong một bước" và sau đó nó đi đến định nghĩa của "bước" - dòng lệnh? tòa nhà cao tầng?
Michael Krelin - tin tặc

1
Tôi vừa nhận thấy rằng bạn đã thêm từ ngữ
tòa nhà

2
@Pascal: không. Trên Solaris, đầu ra từ 'truss ln -spx' và 'truss ln -s -fpx' hiển thị một cuộc gọi unlink () trước cuộc gọi symlink () trong trường hợp thứ hai (và cuộc gọi symlink () thất bại trong lần đầu tiên). Tôi hy vọng điều đó sẽ áp dụng cho hầu hết nếu không phải tất cả các biến thể của Unix.
Jonathan Leffler

12
+1 để nhận xét @Taai - nếu xử lý một liên kết tượng trưng cho các thư mục (trỏ đến) một thư mục, bạn cần chỉ định "-n" để đảm bảo thủ thuật này hoạt động.
wally

161

Vâng, bạn có thể!

$ ln -sfn source_file_or_directory_name softlink_name

9
Cảm ơn bạn đã trả lời. Các -fphương tiện tùy chọn 'loại bỏ các điểm đến hiện' trước khi tạo một hình mới. Vì vậy, lệnh này đạt được kết quả, nhưng bằng cách làm unlink(2)theo sau symlink(2). Đây không phải là những gì câu hỏi ban đầu là về. Cũng lưu ý rằng câu trả lời được chấp nhận và câu trả lời được bình chọn nhiều nhất tiếp theo đều được sử dụng ln -sfđể thực hiện công việc, nhưng như straceđầu ra cho thấy, nó thực hiện unlink()symlink()bởi vì không có cuộc gọi hệ thống để sửa đổi liên kết tượng trưng.
Jonathan Leffler

17
-N dường như được yêu cầu khi liên kết ban đầu đi đến một thư mục thay vì một tập tin.
steampowered

11
Công tắc 'n' rất quan trọng. Tôi đã vật lộn với vấn đề là liên kết tượng trưng không được cập nhật nhưng lệnh đã tạo một liên kết khác bên trong liên kết hiện có vì tùy chọn 'không hủy đăng ký' không được đặt.
Jonathan Gruber

14

Không cần thiết phải hủy liên kết symlink cũ. Bạn có thể làm được việc này:

ln -s newtarget temp
mv temp mylink

(hoặc sử dụng các liên kết tượng trưng tương đương và đổi tên cuộc gọi). Điều này tốt hơn so với việc hủy liên kết rõ ràng vì đổi tên là nguyên tử, vì vậy bạn có thể yên tâm rằng liên kết sẽ luôn hướng đến mục tiêu cũ hoặc mới. Tuy nhiên điều này sẽ không sử dụng lại các nút gốc.

Trên một số hệ thống tập tin, mục tiêu của liên kết tượng trưng được lưu trữ trong chính nút (thay cho danh sách khối) nếu nó đủ ngắn; điều này được xác định tại thời điểm nó được tạo ra.

Liên quan đến khẳng định rằng chủ sở hữu và nhóm thực tế là không quan trọng, symlink (7) trên Linux nói rằng có một trường hợp quan trọng:

Chủ sở hữu và nhóm của một liên kết tượng trưng hiện có có thể được thay đổi bằng cách sử dụng lchown (2). Lần duy nhất quyền sở hữu của một liên kết tượng trưng là khi liên kết bị xóa hoặc đổi tên trong một thư mục có tập bit dính (xem stat (2)).

Truy cập cuối cùng và dấu thời gian sửa đổi cuối cùng của một liên kết tượng trưng có thể được thay đổi bằng cách sử dụng utplesat (2) hoặc lutimes (3).

Trên Linux, các quyền của liên kết tượng trưng không được sử dụng trong bất kỳ hoạt động nào; các quyền luôn luôn là 0777 (đọc, viết và thực thi cho tất cả các loại người dùng) và không thể thay đổi.


@ mark4o: The Good - Tham chiếu đến lchown () và quyền sở hữu trong thư mục dính-it rất hữu ích - cảm ơn. Tôi đã nhận thức được lchown () và nó không phải là tài liệu cho luận án của tôi. Tôi cũng nhận thức được các thư mục dính-bit; Tôi nghĩ rằng quyền sở hữu gần như là hệ quả tiêu chuẩn của các quy tắc - sự khác biệt và có lẽ là lý do tại sao nó được gọi ra, đó là thông thường bạn có thể xóa một tệp nếu bạn có thể ghi vào đó và trên danh nghĩa, bất kỳ ai cũng có thể viết vào một liên kết tượng trưng bởi vì trong số các quyền 777, nhưng trong trường hợp này, các quy tắc hơi khác nhau.
Jonathan Leffler

1
@ mark4o: Không tốt lắm - chuỗi lệnh được hiển thị không làm những gì bạn nghĩ nó (ít nhất, trong kịch bản set -x -e; mkdir junk; ( cd junk; mkdir olddir newdir; ln -s olddir mylink; ls -ilR; ln -s newdir temp; ls -ilR; mv temp mylink; ls -ilR; ); rm -fr junk:). Nếu bạn tạo tệp oldfile và newfile thay vì thư mục và chạy tập lệnh tương đương (chủ yếu thay đổi olddir thành oldfile, newdir thành newfile), thì bạn sẽ nhận được hiệu quả mà bạn mong đợi. Chỉ cần thêm một sự phức tạp! Cảm ơn bạn đã phản hồi.
Jonathan Leffler

2

Chỉ cần một cảnh báo cho câu trả lời đúng ở trên:

Sử dụng Phương thức -f / --force sẽ gây rủi ro mất tệp nếu bạn trộn lẫn nguồn và đích:

mbucher@server2:~/test$ ls -la
total 11448
drwxr-xr-x  2 mbucher www-data    4096 May 25 15:27 .
drwxr-xr-x 18 mbucher www-data    4096 May 25 15:13 ..
-rw-r--r--  1 mbucher www-data 4109466 May 25 15:26 data.tar.gz
-rw-r--r--  1 mbucher www-data 7582480 May 25 15:27 otherdata.tar.gz
lrwxrwxrwx  1 mbucher www-data      11 May 25 15:26 thesymlink -> data.tar.gz
mbucher@server2:~/test$ 
mbucher@server2:~/test$ ln -s -f thesymlink otherdata.tar.gz 
mbucher@server2:~/test$ 
mbucher@server2:~/test$ ls -la
total 4028
drwxr-xr-x  2 mbucher www-data    4096 May 25 15:28 .
drwxr-xr-x 18 mbucher www-data    4096 May 25 15:13 ..
-rw-r--r--  1 mbucher www-data 4109466 May 25 15:26 data.tar.gz
lrwxrwxrwx  1 mbucher www-data      10 May 25 15:28 otherdata.tar.gz -> thesymlink
lrwxrwxrwx  1 mbucher www-data      11 May 25 15:26 thesymlink -> data.tar.gz

Tất nhiên điều này là có ý định, nhưng thường xảy ra sai lầm. Vì vậy, xóa và xây dựng lại liên kết tượng trưng là công việc nhiều hơn một chút nhưng cũng tiết kiệm hơn một chút:

mbucher@server2:~/test$ rm thesymlink && ln -s thesymlink otherdata.tar.gz 
ln: creating symbolic link `otherdata.tar.gz': File exists

mà ít nhất giữ tập tin của tôi.


Sử dụng một -fhoặc --forcetùy chọn luôn luôn là một chút nguy hiểm; nó cho rằng người dùng biết họ đang nói gì. Nó sẽ gây chết người gấp đôi nếu bạn sử dụng nó theo thói quen ( rm -fr …mỗi lần đều nguy hiểm).
Jonathan Leffler

1

Dù sao cuối cùng cũng không hủy liên kết nó và tạo cái mới sẽ làm điều tương tự?


2
Tại sao bỏ liên kết ở nơi đầu tiên? Tại sao không đơn giản ghi đè lên nó?
S.Lott

5
Kết quả cuối cùng xấp xỉ nhau - nhưng nói chung, chủ sở hữu và nhóm và lần sửa đổi cuối cùng (và có lẽ là số inode) sẽ khác nhau, nói chung.
Jonathan Leffler

2
@ S.Lott: 'ghi đè' hệ thống gọi là gì? Trong POSIX, không có cuộc gọi như vậy. Trong Solaris và MacOS X, không có cuộc gọi như vậy. Có một cuộc gọi để làm điều đó trên ... Linux, AIX, HP-UX, bất cứ thứ gì khác trông giống Unix không? Windows không thực sự có các liên kết tượng trưng theo cùng một cách, AFAICT, vì vậy nó không quan trọng đối với phân tích của tôi - nhưng thông tin về API Windows tương đương sẽ hữu ích.
Jonathan Leffler

@Jonathan Leffler: Ummm .... ln --forcelệnh sẽ hoàn toàn ghi đè lên một liên kết hiện có.
S.Lott

Các bạn, tôi nghĩ rằng bạn đang nói chuyện với mục đích chéo. S.Lott đang thảo luận về một thực thi ln (1), trong khi matt b. đang thảo luận thực tế là symlink (2)không không hỗ trợ ghi đè. Bạn đều đúng, và tôi sẽ đề nghị rằng việc xem xét việc thực hiện ln (1)sẽ đưa ra cách thức hoàn hảo nhất để thực hiện thủ tục hủy liên kết.
dmckee --- ex-moderator mèo con

0

Chỉ trong trường hợp nó giúp: có một cách để chỉnh sửa một liên kết tượng trưng với chỉ huy nửa đêm (mc). Lệnh menu là (bằng tiếng Pháp trên giao diện mc của tôi):

Fichier / Éditer le lien symbolique

có thể được dịch thành:

File / Edit symbolic link

Phím tắt là Cx Cs

Có lẽ nó sử dụng ln --forcelệnh bên trong , tôi không biết.

Bây giờ, tôi đang cố gắng tìm cách chỉnh sửa toàn bộ nhiều liên kết cùng một lúc (đó là cách tôi đến đây).


1
Bạn đã xác minh những gì MC làm đằng sau hậu trường? Tôi đặt cược rằng trên thực tế, nó unlink()đi theo sau symlink(), đơn giản vì đó là những gì các hệ thống giống Unix cung cấp.
Jonathan Leffler

Không, tôi chưa kiểm tra. Và đúng vậy, thực tế là nó có thể xảy ra như bạn nói, trên thực tế. Việc tôi chỉnh sửa một hộp văn bản mang lại cảm giác rằng tôi thực sự đang chỉnh sửa mục tiêu liên kết tượng trưng, ​​nhưng có lẽ tôi đã bị lừa ...
Pierre

0

Về mặt kỹ thuật, không có lệnh tích hợp để chỉnh sửa một liên kết tượng trưng hiện có. Nó có thể dễ dàng đạt được với một vài lệnh ngắn.

Đây là một hàm bash / zsh nhỏ mà tôi đã viết để cập nhật một liên kết tượng trưng hiện có:

# -----------------------------------------
# Edit an existing symbolic link
#
# @1 = Name of symbolic link to edit
# @2 = Full destination path to update existing symlink with 
# -----------------------------------------
function edit-symlink () {
    if [ -z "$1" ]; then
        echo "Name of symbolic link you would like to edit:"
        read LINK
    else
        LINK="$1"
    fi
    LINKTMP="$LINK-tmp"
    if [ -z "$2" ]; then
        echo "Full destination path to update existing symlink with:"
        read DEST
    else
        DEST="$2"
    fi
    ln -s $DEST $LINKTMP
    rm $LINK
    mv $LINKTMP $LINK
    printf "Updated $LINK to point to new destination -> $DEST"
}

2
Cảm ơn vì nỗ lực của bạn. Điều này không đáp ứng yêu cầu của tôi là một cuộc gọi hệ thống ngôn ngữ C. Có rất nhiều cách để thay đổi một liên kết miễn là bạn có quyền ghi trên thư mục giữ liên kết (điều này đòi hỏi). Ngay cả bây giờ, không có cách nào tôi biết để thay đổi giá trị của một liên kết tượng trưng mà không làm unlink()symlink()với giá trị mới, đó là những gì diễn ra sau hậu trường với mã của bạn. Cá nhân, tôi có chức năng nhấn mạnh vào chính xác hai (hoặc có thể là bội số của hai) đối số và bảo lãnh nếu lời gọi không đúng. Đó là một quan điểm cụ thể, mặc dù.
Jonathan Leffler
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.