Xác định nếu một tập tin là một liên kết cứng hoặc liên kết tượng trưng?


51

Tôi đang tạo một tập lệnh shell sẽ đưa tên tệp / đường dẫn đến một tệp và xác định xem tệp đó là liên kết tượng trưng hay liên kết cứng.

Điều duy nhất là, tôi không biết làm thế nào để xem chúng có phải là một liên kết cứng hay không. Tôi đã tạo 2 tệp, một liên kết cứng và một liên kết tượng trưng, ​​để sử dụng làm tệp thử nghiệm. Nhưng làm cách nào để xác định xem một tệp là một liên kết cứng hoặc tượng trưng trong tập lệnh shell?

Ngoài ra, làm thế nào tôi có thể tìm thấy phân vùng đích của một liên kết tượng trưng? Vì vậy, hãy nói rằng tôi có một tệp liên kết đến một phân vùng khác, làm thế nào tôi có thể tìm thấy đường dẫn đến tệp gốc đó?


16
Bạn có ý nghĩa gì bởi liên kết cứng? Tất cả các tập tin là liên kết cứng.
terdon

1
@terdon ln /foo/bar/ /foo/bar2tạo một ln -s /foo/bar /foo/bar2liên kết cứng trong khi tạo một liên kết tượng trưng, ​​đó có nghĩa là gì?
DisplayName

14
@DisplayName có, nhưng tất cả các tệp là các liên kết cứng đến nút inode của chúng. Đó là cách hệ thống tập tin Linux hoạt động. Trong ví dụ của bạn, bar2barlà cả hai liên kết cứng, chỉ trỏ đến cùng một nút.
terdon

10
@DisplayName có, họ là các liên kết khó khác inodes . Không có mâu thuẫn ở đây. Một tập tin là một liên kết đến một nút. Đó là định nghĩa của một tập tin. Trong trường hợp của bạn, bạn có các liên kết này ở những nơi khác nhau nhưng điều đó không thay đổi cấu trúc dữ liệu cơ bản. Quan điểm của tôi là cả hai barbar2đều quan trọng như nhau. Một cái không phải là liên kết với cái kia, cả hai đều là liên kết nhưng trỏ đến cùng một nút.
terdon

3
@ Không, tôi đang nói rằng các tệp thông thường là các liên kết cứng và các liên kết cứng được tạo bởi lnkhông khác gì các tệp thông thường.
terdon

Câu trả lời:


42

Câu trả lời của Jim giải thích làm thế nào để kiểm tra một liên kết tượng trưng: bằng cách sử dụng test's -Lkiểm tra.

Nhưng kiểm tra cho một "liên kết cứng" là, tốt, nói đúng không phải là những gì bạn muốn. Liên kết cứng hoạt động vì cách Unix xử lý tệp: mỗi tệp được biểu thị bằng một nút đơn. Sau đó, một nút đơn có 0 hoặc nhiều tên hoặc mục nhập thư mục hoặc, về mặt kỹ thuật, các liên kết cứng (cái mà bạn đang gọi là "tệp").

Rất may, statlệnh, nếu có, có thể cho bạn biết có bao nhiêu tên một nút.

Vì vậy, bạn đang tìm kiếm một cái gì đó như thế này (ở đây giả sử triển khai GNU hoặc busybox stat):

if [ "$(stat -c %h -- "$file")" -gt 1 ]; then
    echo "File has more than one name."
fi

Các -c '%h'chút nói statđể chỉ ra số lượng liên kết cứng đến inode, tức là, số lượng các tên file có. -gt 1sau đó kiểm tra nếu đó là nhiều hơn 1.

Lưu ý rằng các liên kết tượng trưng, ​​giống như bất kỳ tệp nào khác, cũng có thể được liên kết với một số thư mục để bạn có thể có một số liên kết cứng đến một liên kết tượng trưng.


ok, để rõ ràng, tôi có thể xuất số lượng liên kết cứng mà tệp đã sử dụng lệnh stat và nếu nó lớn hơn 1, thì nó có một tệp khác được liên kết ở đâu đó trên phân vùng.
k-Rocker

@ k-Rocker Có. Sau đó, nó có một tên thứ hai ở đâu đó trên phân vùng.
derobert

1
Trên OS X hoặc * BSD, nó stat -f %l /path/to/file. Bạn cũng có thể sử dụng gstat -c %h /path/to/filenếu bạn đã cài đặt lõi GNU mà không có tên mặc định của chúng (với Homebrew trên OS X).
GDP2

29

Một ví dụ:

$ touch f1
$ ln f1 f2
$ ln f1 f3
$ ln -s f1 s1
$ ln -s f2 s2
$ ln -s ./././f3 s3
$ ln -s s3 s4
$ ln s4 s5
$ ls -li
total 0
10802124 -rw-r--r-- 3 stephane stephane 0 Nov 12 19:55 f1
10802124 -rw-r--r-- 3 stephane stephane 0 Nov 12 19:55 f2
10802124 -rw-r--r-- 3 stephane stephane 0 Nov 12 19:55 f3
10802345 lrwxrwxrwx 1 stephane stephane 2 Nov 12 19:56 s1 -> f1
10802346 lrwxrwxrwx 1 stephane stephane 2 Nov 12 19:56 s2 -> f2
10802347 lrwxrwxrwx 1 stephane stephane 8 Nov 12 19:56 s3 -> ./././f3
10802384 lrwxrwxrwx 2 stephane stephane 2 Nov 12 19:56 s4 -> s3
10802384 lrwxrwxrwx 2 stephane stephane 2 Nov 12 19:56 s5 -> s3

Các f1, f2f3mục thư mục đều giống nhau tập tin (giống inode: 10.802.124, bạn sẽ nhận thấy số lượng liên kết là 3). Chúng là các liên kết cứng đến cùng một tệp thông thường .

s4s5cũng là cùng một tệp (10802384). Chúng thuộc loại symlink , không thường xuyên . Họ chỉ ra một con đường, ở đây s3. Bởi vì s4s5là các mục của cùng một thư mục, đường dẫn tương đối s3đó trỏ đến cùng một tệp (tệp có inod 10802347) cho cả hai.

Nếu bạn làm một ls -Ll, đó là yêu cầu lấy thông tin tệp sau khi giải quyết các liên kết tượng trưng:

$ ls -lLi
total 0
10802124 -rw-r--r-- 3 stephane stephane 0 Nov 12 19:55 f1
10802124 -rw-r--r-- 3 stephane stephane 0 Nov 12 19:55 f2
10802124 -rw-r--r-- 3 stephane stephane 0 Nov 12 19:55 f3
10802124 -rw-r--r-- 3 stephane stephane 0 Nov 12 19:55 s1
10802124 -rw-r--r-- 3 stephane stephane 0 Nov 12 19:55 s2
10802124 -rw-r--r-- 3 stephane stephane 0 Nov 12 19:55 s3
10802124 -rw-r--r-- 3 stephane stephane 0 Nov 12 19:55 s4
10802124 -rw-r--r-- 3 stephane stephane 0 Nov 12 19:55 s5

Bạn sẽ thấy tất cả đều giải quyết cùng một tệp (10802124).

Bạn có thể kiểm tra nếu một tập tin là một liên kết tượng trưng với [ -L file ]. Tương tự, bạn có thể kiểm tra xem một tệp có phải là tệp thông thường hay không [ -f file ], nhưng trong trường hợp đó, kiểm tra được thực hiện sau khi giải quyết các liên kết tượng trưng.

liên kết cứng không phải là một loại tệp, chúng chỉ là các tên khác nhau cho một tệp (thuộc bất kỳ loại nào).


19

Sử dụng -hvà các -Ltoán tử của testlệnh:

-h file 
true if file is a symbolic link

-L file 
true if file is a symbolic link

http://www.mkssoftware.com/docs/man1/test.1.asp

Theo chủ đề SO này , họ có hành vi tương tự, nhưng -Lđược ưa thích.


ok tuyệt, nhưng những gì về liên kết cứng? tôi đã kiểm tra bước đi, nhưng không có gì về liên kết cứng. Nếu -L trả về false, điều đó có nghĩa là liên kết cứng phải không? hay chỉ là một tập tin thông thường?
k-Rocker

1
Liên kết cứng chia sẻ như nhau inode. Ngoài ra, các liên kết mềm hiển thị lở đầu đầu ra của nó ls -l... Tôi nghĩ rằng bạn có thể đặt các quy tắc đó lại với nhau trong một tập lệnh, cộng với [[ -L file ]]thử nghiệm để xem liệu tệp đã cho là mềm hay cứng .
jimm-cl

ok, ngoài ra, làm thế nào tôi tìm thấy phân vùng đích của liên kết tượng trưng?
k-Rocker

3

Có rất nhiều câu trả lời khá chính xác ở đây, nhưng tôi không nghĩ có ai thực sự giải quyết được sự hiểu lầm ban đầu. Câu hỏi ban đầu về cơ bản là "khi tôi tạo một liên kết tượng trưng, ​​thật dễ dàng để xác định nó sau đó. Nhưng tôi không thể tìm ra cách xác định một liên kết cứng." Và vâng, các câu trả lời về cơ bản sôi nổi thành "bạn không thể", và ít nhiều giải thích lý do tại sao, nhưng dường như không ai thừa nhận rằng, thực sự, nó khó hiểu và kỳ lạ.

Nếu bạn đang đọc tất cả những điều này và bạn đã tìm ra điều gì đang xảy ra, thì bạn tốt; bạn không cần phải đọc một chút của tôi. Nếu bạn vẫn còn bối rối, thì hãy tiếp tục.

Câu trả lời thực sự rất ngắn là một liên kết cứng hoàn toàn không phải là một liên kết, không phải theo cách liên kết tượng trưng. Đây là một mục mới trong cấu trúc thư mục trỏ đến cùng một byte mà mục nhập thư mục gốc đã làm, và một khi bạn đã tạo nó, nó giống như 'thực' và hợp pháp như cái đầu tiên. Mỗi tệp 'bình thường' trên ổ đĩa của bạn có ít nhất một liên kết cứng; không có điều đó, bạn sẽ không thấy nó trong bất kỳthư mục, và sẽ không thể đề cập đến nó hoặc sử dụng nó. Vì vậy, nếu bạn có tệp Fred.txt và bạn liên kết cứng Wilma.txt và Barney.txt với nó, cả ba tên (và mục nhập thư mục) đều tham chiếu đến cùng một tệp và chúng đều có giá trị như nhau. HĐH không có cách nào để nói rằng một trong những mục được tạo khi bạn nhấn "lưu" trong trình soạn thảo văn bản của mình và các mục khác được tạo bằng lệnh "ln".

Các hệ điều hành không phải theo dõi có bao nhiêu mục khác nhau được trỏ đến cùng một tập tin, mặc dù. Nếu bạn xóa Wilma.txt, không có gì ngạc nhiên khi bạn không giải phóng bất kỳ dung lượng nào trên ổ đĩa của mình. Nhưng nếu bạn xóa Fred.txt (tệp 'gốc'), bạn vẫn sẽ không giải phóng bất kỳ dung lượng nào trên ổ đĩa của mình, vì dữ liệu trên ổ đĩa được gọi là Fred.txt vẫn là Barney.txt. Chỉ khi bạn xóa tất cả các mục trong thư mục, HĐH mới phân bổ lại không gian mà dữ liệu đang chiếm giữ.

Nếu Barney.txt là một liên kết tượng trưng, ​​thì việc xóa Fred.txt sẽ được phân bổ lại không gian và Barney.txt bây giờ sẽ là một liên kết bị hỏng. Ngoài ra, nếu bạn di chuyển hoặc đổi tên một tệp có liên kết tượng trưng chỉ vào nó, bạn sẽ phá vỡ liên kết. Nhưng bạn có thể di chuyển hoặc đổi tên một tệp được liên kết cứng tất cả những gì bạn muốn mà không phá vỡ các mục nhập thư mục khác trỏ đến tệp / dữ liệu đó, bởi vì tất cả chúng đều là các mục nhập thư mục tham chiếu đến cùng một khối dữ liệu trên ổ đĩa (bằng cách sử dụng inode # của dữ liệu đó).

[Đó là hai năm sau, và điều đó cuối cùng làm tôi bối rối trong một phút, vì vậy tôi nghĩ tôi sẽ làm rõ. Nếu bạn nhập "mv ./Wilma.txt ../elsewhere/Betty.txt" thì có vẻ như bạn đang di chuyển tệp, nhưng thực tế, bạn không làm vậy. Những gì bạn thực sự đang làm là xóa một mục hàng khỏi danh sách thư mục của thư mục hiện tại của bạn, mục có tên "Wilma.txt" được liên kết với dữ liệu có thể được tìm thấy bằng cách sử dụng inode ####### #, "và thêm một mục hàng mới vào danh sách thư mục của thư mục ../elsewhere có tên" tên 'Betty.txt' được liên kết với dữ liệu có thể được tìm thấy qua inode ####### ". Đây là lý do tại sao bạn có thể 'di chuyển' tệp 2 gigabyte nhanh như tệp 2 kilobyte, miễn là bạn đang di chuyển chúng đến một vị trí khác trên cùng một ổ đĩa.]

Vì HĐH phải theo dõi xem có bao nhiêu mục nhập thư mục khác nhau đang trỏ đến cùng một khối dữ liệu, bạn có thể biết liệu một tệp cụ thể có được liên kết cứng hay không, mặc dù bạn không thể biết chắc chắn liệu mục nhập thư mục đó có phải là bạn không "Đang xem có phải là" bản gốc "hay không. Một cách là lệnh "ls", cụ thể là "ls -l" (đó là chữ L viết thường sau dấu gạch ngang)

Để mượn một ví dụ trước đó ....

 -rw-r--r-- 3 stephane stephane 0 Nov 12 19:55 f1

Chữ cái đầu tiên là một dấu gạch ngang, vì vậy nó không phải là một thư mục hoặc một cái gì đó kỳ lạ, đó là một tệp thông thường 'thông thường'. Nhưng nếu nó thực sự bình thường, con số đó sau phần rwx-ish sẽ là "1", như trong "có một mục nhập thư mục trỏ đến khối dữ liệu này." Nhưng đó là một phần của một cuộc biểu tình của các liên kết cứng, vì vậy thay vào đó nó nói "3".

Lưu ý rằng điều này có thể có thể dẫn đến hành vi kỳ lạ và bí ẩn (nếu bạn không quấn đầu quanh các liên kết cứng, đó là). Nếu bạn mở Fred.txt trong trình soạn thảo văn bản của mình và thực hiện một số thay đổi, bạn sẽ thấy những thay đổi tương tự trong Wilma.txt và Barney.txt? Có lẽ. Có lẽ. Nếu trình soạn thảo văn bản của bạn lưu các thay đổi bằng cách mở tệp gốc và viết các thay đổi cho nó, thì có, cả ba tên sẽ vẫn được trỏ vào cùng một văn bản (mới được thay đổi). Nhưng nếu trình soạn thảo văn bản của bạn tạo một tệp mới (Fred-new-temp.txt), hãy viết phiên bản đã thay đổi của bạn thành đó, sau đó xóa Fred.txt, sau đó đổi tên Fred-new-temp.txt thành Fred.txt, Wilma và Barney sẽ vẫn được trỏ đến phiên bản gốc, không phải phiên bản mới thay đổi. Nếu bạn không hiểu các liên kết cứng, điều này có thể khiến bạn hơi phát điên. :) [Được rồi, tôi thực sự không biết cá nhântrình soạn thảo văn bản sẽ thực hiện điều mới / đổi tên, nhưng tôi biết rất nhiều chương trình khác thực hiện chính xác điều đó, vì vậy hãy cảnh giác.]

Lưu ý cuối cùng: một trong những điều mà 'fsck' (kiểm tra hệ thống tệp) kiểm tra là nếu có khối dữ liệu trên ổ đĩa của bạn mà bằng cách nào đó không còn được tham chiếu bởi bất kỳ mục nhập thư mục nào. Đôi khi có lỗi xảy ra và mục nhập thư mục duy nhất trỏ đến một nút bị xóa nhưng không gian ổ đĩa không được đánh dấu là "có sẵn". Vì vậy, một trong những công việc của fsck là khớp tất cả không gian được phân bổ với tất cả các mục trong thư mục để đảm bảo rằng không có bất kỳ tệp nào không được ước tính. Nếu nó tìm thấy một số, nó tạo ra các mục thư mục mới và đặt chúng vào "mất + tìm thấy".


Chỉ cần tự hỏi, những "chương trình khác làm chính xác điều đó" là gì?
phk

@phk Không biết cụ thể anh ấy đang nghĩ gì, nhưng đó là một cách tiếp cận đủ phổ biến để thực hiện các hành động có thể mất nhiều thời gian và sẽ khiến bạn rơi vào tình trạng không chắc chắn nếu thất bại. Ví dụ: nếu bạn cố tải xuống từ máy chủ từ xa và bạn biết rằng có khả năng máy chủ có thể hết thời gian, thì một cách tiếp cận sẽ là tải toàn bộ nội dung xuống tệp tạm thời. Theo cách đó, nếu có sự cố xảy ra với quá trình tải xuống, bạn vẫn có tệp gốc.
cwallenpoole

Chương trình duy nhất tôi biết chắc chắn là FreeHand, bởi vì nếu / khi nó gặp sự cố trong quá trình lưu, sẽ có một tệp tạm thời bị bỏ lại, thay vì một tệp gốc bị xáo trộn. Nhưng tôi đã thấy các chương trình khác cũng làm điều đó; Tôi chỉ không thể cho bạn ví dụ cụ thể tại thời điểm này.
Snarke

2

bạn có thể sử dụng readlink FILE; echo $?. Điều này trả về 1 khi đó là liên kết cứng và 0 khi đó là liên kết tượng trưng.

Từ trang man: "Khi được gọi là readlink, chỉ có mục tiêu của liên kết tượng trưng được in. Nếu đối số đã cho không phải là liên kết tượng trưng, ​​readlink sẽ in không có gì và thoát với lỗi."

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.