Làm thế nào tôi có thể tìm thấy các liên kết bị hỏng


282

Có cách nào để tìm tất cả các liên kết tượng trưng mà không chỉ ra được không?

find ./ -type l

sẽ cung cấp cho tôi tất cả các liên kết tượng trưng, ​​nhưng không phân biệt giữa các liên kết đi đâu đó và các liên kết không.

Tôi hiện đang làm:

find ./ -type l -exec file {} \; |grep broken

Nhưng tôi đang tự hỏi những giải pháp thay thế tồn tại.

Câu trả lời:


351

Tôi thực sự khuyên bạn không nên sử dụng find -L cho nhiệm vụ (xem bên dưới để giải thích). Dưới đây là một số cách khác để làm điều này:

  • Nếu bạn muốn sử dụng một findphương thức " thuần túy ", nó sẽ trông giống như thế này:

    find . -xtype l
    

    ( xtypelà một thử nghiệm được thực hiện trên một liên kết bị loại bỏ) Tuy nhiên, điều này có thể không có sẵn trong tất cả các phiên bản find. Nhưng cũng có những lựa chọn khác:

  • Bạn cũng có thể thực thi test -etừ bên trong findlệnh:

    find . -type l ! -exec test -e {} \; -print
    
  • Thậm chí một số grepmẹo có thể tốt hơn (nghĩa là an toàn hơn ) find -L, nhưng không chính xác như được trình bày trong câu hỏi (mà greps trong toàn bộ các dòng đầu ra, bao gồm cả tên tệp):

     find . -type l -exec sh -c 'file -b "$1" | grep -q ^broken' sh {} \; -print
    

Thủ find -Lthuật được trích dẫn bởi solo từ Commandlinefu trông rất hay và hack, nhưng nó có một cạm bẫy rất nguy hiểm : Tất cả các liên kết tượng trưng đều được tuân theo. Xem xét thư mục với các nội dung được trình bày dưới đây:

$ ls -l
total 0
lrwxrwxrwx 1 michal users  6 May 15 08:12 link_1 -> nonexistent1
lrwxrwxrwx 1 michal users  6 May 15 08:13 link_2 -> nonexistent2
lrwxrwxrwx 1 michal users  6 May 15 08:13 link_3 -> nonexistent3
lrwxrwxrwx 1 michal users  6 May 15 08:13 link_4 -> nonexistent4
lrwxrwxrwx 1 michal users 11 May 15 08:20 link_out -> /usr/share/

Nếu bạn chạy find -L . -type ltrong thư mục đó, tất cả /usr/share/cũng sẽ được tìm kiếm (và điều đó có thể mất nhiều thời gian) 1 . Đối với một findlệnh "miễn dịch với các liên kết đi", không sử dụng-L .


1 Điều này có thể trông giống như một bất tiện nhỏ (lệnh sẽ "chỉ" mất nhiều thời gian để vượt qua tất cả /usr/share) - nhưng có thể có hậu quả nghiêm trọng hơn. Ví dụ, hãy xem xét các môi trường chroot: Chúng có thể tồn tại trong một số thư mục con của hệ thống tệp chính và chứa các liên kết tượng trưng đến các vị trí tuyệt đối. Những liên kết đó dường như có thể bị phá vỡ đối với hệ thống "bên ngoài", bởi vì chúng chỉ trỏ đến những nơi thích hợp khi bạn đã vào chroot. Tôi cũng nhớ lại rằng một số bộ nạp khởi động đã sử dụng các liên kết tượng trưng theo /bootđó chỉ có ý nghĩa trong giai đoạn khởi động ban đầu, khi phân vùng khởi động được gắn kết là /.

Vì vậy, nếu bạn sử dụng một find -Llệnh để tìm và sau đó xóa các liên kết tượng trưng bị hỏng khỏi một thư mục trông vô hại, bạn thậm chí có thể phá vỡ hệ thống của mình ...


11
Tôi nghĩ -type llà dư thừa vì -xtype lsẽ hoạt động như -type ltrên không liên kết. Vì vậy, find -xtype lcó lẽ là tất cả những gì bạn cần. Cảm ơn vì cách tiếp cận này.
quornian

3
Xin lưu ý rằng các giải pháp đó không hoạt động đối với tất cả các loại hệ thống tệp. Ví dụ, nó sẽ không hoạt động để kiểm tra nếu /proc/XXX/exeliên kết bị hỏng. Đối với điều này, sử dụng test -e "$(readlink /proc/XXX/exe)".
qwertzguy

2
@Flimm find . -xtype lcó nghĩa là "tìm tất cả các liên kết có tệp mục tiêu (cuối cùng) là liên kết tượng trưng". Nhưng mục tiêu cuối cùng của một liên kết tượng trưng không thể là một liên kết tượng trưng, ​​nếu không chúng ta vẫn có thể theo liên kết đó và nó không phải là mục tiêu cuối cùng. Vì không có các liên kết tượng trưng như vậy, chúng ta có thể định nghĩa chúng là một cái gì đó khác, tức là các liên kết tượng trưng bị hỏng.
yếu

2
@ JoóÁdám "chỉ có thể là một liên kết tượng trưng trong trường hợp nó bị hỏng". Cung cấp cho "liên kết tượng trưng bị hỏng" hoặc "tệp không tồn tại" một loại riêng lẻ, thay vì quá tải l, ít gây nhầm lẫn với tôi.
yếu

3
Cảnh báo ở cuối là hữu ích, nhưng lưu ý rằng điều này không áp dụng cho -Lhack mà là (loại bỏ) một cách mù quáng nói chung.
Alois Mahdal


32

Như rozcietrzewiacz đã nhận xét, find -Lcó thể có hậu quả bất ngờ của việc mở rộng tìm kiếm vào các thư mục được liên kết, do đó không phải là phương pháp tối ưu. Điều chưa ai nhắc đến là

find /path/to/search -xtype l

là lệnh ngắn gọn và hợp lý hơn với

find /path/to/search -type l -xtype l

Không có giải pháp nào được trình bày cho đến nay sẽ phát hiện các liên kết theo chu kỳ, đó là một loại phá vỡ khác. câu hỏi này giải quyết tính di động. Tóm lại, cách di động để tìm các liên kết tượng trưng bị hỏng, bao gồm các liên kết tuần hoàn, là:

find /path/to/search -type l -exec test ! -e {} \; -print

Để biết thêm chi tiết, xem câu hỏi này hoặc ynform.org . Tất nhiên, nguồn chính xác cho tất cả điều này là tài liệu findutils .


1
Ngắn, sự đồng ý và giải quyết các find -Lcạm bẫy cũng như các liên kết theo chu kỳ. +1
Flimm

Đẹp. Cái cuối cùng cũng hoạt động trên MacOSX, trong khi câu trả lời của @ rozcietrzewiacz thì không.
neu242

1
@ neu242 Điều đó có thể là do -xtypekhông được chỉ định trong POSIX và thực sự nếu bạn xem find(1)trong macOS thì có -typenhưng không -xtype .
Pryftan

7

Tôi tin rằng việc thêm -Lcờ vào lệnh của bạn sẽ cho phép bạn thoát khỏi grep:

$ find -L . -type l

http://www.commandlinefu.com/commands/view/8260/find-broken-symlinks

từ người đàn ông:

 -L      Cause the file information and file type (see stat(2)) returned 
         for each symbolic link to be those of the file referenced by the
         link, not the link itself. If the referenced file does not exist,
         the file information and type will be for the link itself.

19
Lúc đầu, tôi đã ủng hộ điều này, nhưng sau đó tôi đã nhận ra nó nguy hiểm như thế nào . Trước khi bạn sử dụng nó, xin vui lòng xem câu trả lời của tôi !
rozcietrzewiacz

6

Nếu bạn cần một hành vi khác cho dù liên kết bị hỏng hoặc theo chu kỳ, bạn cũng có thể sử dụng% Y với find:

$ touch a
$ ln -s a b  # link to existing target
$ ln -s c d  # link to non-existing target
$ ln -s e e  # link to itself
$ find . -type l -exec test ! -e {} \; -printf '%Y %p\n' \
   | while read type link; do
         case "$type" in
         N) echo "do something with broken link $link" ;;
         L) echo "do something with cyclic link $link" ;;
         esac
      done
do something with broken link ./d
do something with cyclic link ./e

Ví dụ này được sao chép từ bài đăng này (trang web đã bị xóa) .

Tài liệu tham khảo


Tuy nhiên, một cách viết tắt khác cho những người không có findlệnh không hỗ trợ xtypecó thể bắt nguồn từ đây : find . type l -printf "%Y %p\n" | grep -w '^N'. Khi andy đánh bại tôi với ý tưởng tương tự (cơ bản) trong kịch bản của anh ấy, tôi miễn cưỡng viết nó thành câu trả lời riêng biệt. :)
cú pháp

2

Tôi sử dụng điều này cho trường hợp của tôi và nó hoạt động khá tốt, vì tôi biết thư mục để tìm kiếm các liên kết tượng trưng bị hỏng:

find -L $path -maxdepth 1 -type l

và thư mục của tôi có chứa một liên kết đến /usr/sharenhưng nó không đi qua nó. Liên kết chéo thiết bị và những liên kết hợp lệ cho chroots, v.v. vẫn còn là một cạm bẫy nhưng đối với trường hợp sử dụng của tôi thì nó đủ.


2

Câu trả lời đơn giản không có trí tuệ, đó là một biến thể trên phiên bản của OP. Đôi khi, bạn chỉ muốn một cái gì đó dễ gõ hoặc nhớ:

find . | xargs file | grep -i "broken symbolic link"

1

find -L . -type l |xargs symlinks sẽ cung cấp cho bạn thông tin liệu liên kết có tồn tại hay không trên cơ sở tìm kiếm.


1

Điều này sẽ in ra tên của các liên kết tượng trưng bị hỏng trong thư mục hiện tại.

for l in $(find . -type l); do cd $(dirname $l); if [ ! -e "$(readlink $(basename $l))" ]; then echo $l; fi; cd - > /dev/null; done

Hoạt động trong Bash. Không biết về vỏ khác.

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.