ฉันจะหา symlinks ที่ชำรุดได้อย่างไร


282

มีวิธีการค้นหาลิงก์สัญลักษณ์ทั้งหมดที่ไม่ได้ชี้ไปที่ใด?

find ./ -type l

จะให้ลิงก์สัญลักษณ์ทั้งหมดแก่ฉัน แต่ไม่แยกความแตกต่างระหว่างลิงก์ที่ไปที่ใดที่หนึ่งและลิงก์ที่ไม่มี

ฉันกำลังทำ:

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

แต่ฉันสงสัยว่ามีวิธีแก้ปัญหาอื่นใดบ้าง

คำตอบ:


351

ฉันขอแนะนำอย่างยิ่งว่าไม่ควรใช้find -L สำหรับงานนี้ (ดูคำอธิบายด้านล่าง) นี่คือวิธีอื่นในการทำสิ่งนี้:

  • หากคุณต้องการใช้วิธีการ "บริสุทธิ์find" มันควรจะมีลักษณะเช่นนี้:

    find . -xtype l
    

    ( xtypeคือการทดสอบที่ดำเนินการเกี่ยวกับการเชื่อมโยง dereferenced) นี้อาจไม่สามารถใช้ได้ในทุกรุ่นของfindแต่ แต่มีตัวเลือกอื่น ๆ เช่นกัน:

  • คุณยังสามารถเรียกใช้งานtest -eจากภายในfindคำสั่ง:

    find . -type l ! -exec test -e {} \; -print
    
  • แม้กระทั่งgrepเคล็ดลับบางอย่างอาจดีกว่า (กล่าวคือปลอดภัยกว่า) find -Lแต่ไม่ตรงตามที่แสดงในคำถาม (ซึ่ง greps ในบรรทัดเอาต์พุตทั้งหมดรวมถึงชื่อไฟล์):

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

find -Lเคล็ดลับยกมาโดยเดี่ยวจากcommandlinefuดูดีและ hacky แต่ก็มีหนึ่งมากหลุมพรางอันตราย : symlinks ทั้งหมดมีการปฏิบัติตาม พิจารณาไดเรกทอรีที่มีเนื้อหาที่แสดงด้านล่าง:

$ 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/

หากคุณทำงานfind -L . -type lอยู่ในไดเรกทอรีที่ทั้งหมด/usr/share/จะได้รับการสืบค้นเช่นกัน (และที่สามารถใช้เวลานานจริงๆ) 1 สำหรับfindคำสั่งที่เป็น "ภูมิคุ้มกันในการเชื่อมโยงออก" -Lไม่ได้ใช้


1สิ่งนี้อาจดูเหมือนความไม่สะดวกเล็กน้อย (คำสั่งจะ "ใช้" ใช้เวลานานในการสำรวจทั้งหมด/usr/share) - แต่อาจมีผลกระทบรุนแรงกว่านี้ ตัวอย่างเช่นพิจารณาสภาพแวดล้อม chroot: พวกเขาสามารถมีอยู่ในไดเรกทอรีย่อยของระบบไฟล์หลักและมี symlink ไปยังสถานที่ที่แน่นอน ดูเหมือนว่าลิงก์เหล่านั้นจะใช้งานไม่ได้กับระบบ "ออกไปข้างนอก" เพราะมันจะชี้ไปยังสถานที่ที่เหมาะสมเมื่อคุณเข้าสู่ระบบแล้ว ฉันยังจำได้ว่า bootloader บางอย่างที่ใช้ symlinks ภายใต้ความรู้สึกที่ทำเฉพาะในขั้นตอนการบูตเริ่มต้นเมื่อบูตพาร์ทิชันที่ถูกติดตั้งเป็น/boot/

ดังนั้นหากคุณใช้find -Lคำสั่งเพื่อค้นหาและลบ symlink ที่เสียหายจากไดเรกทอรีที่ไม่เป็นอันตรายคุณอาจทำลายระบบของคุณ ...


11
ฉันคิดว่า-type lมีความซ้ำซ้อนเนื่องจาก-xtype lจะทำหน้าที่เป็น-type lลิงก์ที่ไม่ใช่ ดังนั้นfind -xtype lอาจเป็นสิ่งที่คุณต้องการ ขอบคุณสำหรับวิธีการนี้
quornian

3
โปรดระวังว่าโซลูชันเหล่านั้นไม่สามารถใช้ได้กับระบบไฟล์ทุกประเภท ตัวอย่างเช่นมันจะไม่ทำงานสำหรับการตรวจสอบว่า/proc/XXX/exeลิงค์เสีย test -e "$(readlink /proc/XXX/exe)"สำหรับเรื่องนี้ใช้
qwertzguy

2
@Flimm find . -xtype lหมายถึง "ค้นหาsymlink ทั้งหมดที่มีไฟล์เป้าหมาย (ultimate) เป็น symlink" แต่เป้าหมายสุดท้ายของ symlink ไม่สามารถเป็น symlink ไม่เช่นนั้นเรายังสามารถติดตามลิงก์ได้และไม่ใช่เป้าหมายขั้นสุดท้าย เนื่องจากไม่มี symlink ดังกล่าวเราจึงสามารถกำหนดให้มันเป็นอย่างอื่นเช่น symlink ที่ไม่ทำงาน
อ่อนแอ

2
@ JoóÁdám "ซึ่งสามารถใช้เป็นลิงก์สัญลักษณ์ในกรณีที่มันเสีย" การให้ "ลิงก์สัญลักษณ์ที่ใช้งานไม่ได้" หรือ "ไฟล์ที่ไม่มีอยู่" เป็นประเภทบุคคลแทนที่จะทำให้การใช้งานมากเกินไปlจะทำให้ฉันสับสนน้อยลง
อ่อนแอ

3
คำเตือนในตอนท้ายมีประโยชน์ แต่โปรดทราบว่านี่ไม่ได้ใช้กับการ-Lแฮ็ก แต่เป็นการลบ symlink ที่เสียโดยทั่วไป (สุ่มสี่สุ่มห้า)
Alois Mahdal

38

symlinksคำสั่งจากhttp://www.ibiblio.org/pub/Linux/utils/file/symlinks-1.4.tar.gzสามารถนำมาใช้เพื่อระบุ symlinks ความหลากหลายของลักษณะที่มี ตัวอย่างเช่น

$ rm a
$ ln -s a b
$ symlinks .
dangling: /tmp/b -> a

เครื่องมือนี้ใช้กับ osx ได้หรือไม่?
qed

ไม่เป็นไรรับมันรวบรวม
qed

2
เห็นได้ชัดว่าsymlinksติดตั้งไว้ล่วงหน้าบน Fedora
Daniel Jonsson

32

ตามที่ rozcietrzewiacz ได้แสดงความคิดเห็นแล้วfind -Lอาจมีผลที่ไม่คาดคิดจากการขยายการค้นหาไปยังไดเรกทอรีที่เชื่อมโยงกันดังนั้นจึงไม่ใช่วิธีที่ดีที่สุด สิ่งที่ไม่มีใครพูดถึงก็คือ

find /path/to/search -xtype l

เป็นคำสั่งที่กระชับและมีเหตุผลเหมือนกัน

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

ไม่มีวิธีแก้ปัญหาใด ๆ ที่นำเสนอในขณะนี้ที่จะตรวจจับไซคลิกซิลิกอนซึ่งเป็นความแตกหักประเภทอื่น คำถามนี้เน้นความสะดวกในการพกพา เพื่อสรุปวิธีพกพาในการค้นหาลิงก์สัญลักษณ์ที่เสียรวมถึงลิงก์ไซคลิกคือ:

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

สำหรับรายละเอียดเพิ่มเติมโปรดดูที่คำถามนี้หรือynform.org แน่นอนว่าแหล่งที่ชัดเจนสำหรับทุกนี้เป็นfindutils documentaton


1
สั้น, consice, และที่อยู่ที่เป็นfind -Lอันตรายเช่นเดียวกับการเชื่อมโยงวงจร +1
Flimm

ดี อันสุดท้ายใช้ได้กับ MacOSX ในขณะที่คำตอบของ @ rozcietrzewiacz ไม่ได้
neu242

1
@ neu242 นั่นอาจเป็นเพราะ-xtypeไม่ได้ระบุไว้ใน POSIX และแน่นอนหากดูfind(1)ใน MacOS ก็มี-typeแต่ไม่ได้ -xtype
Pryftan

7

ฉันเชื่อว่าการเพิ่ม-Lค่าสถานะลงในคำสั่งของคุณจะช่วยให้คุณกำจัด grep ได้:

$ find -L . -type l

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

จากผู้ชาย:

 -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
ตอนแรกฉันได้ upvoting นี้ แต่แล้วฉันก็รู้ว่ามันอันตรายแค่ไหน ก่อนที่คุณจะใช้โปรดดูคำตอบของฉัน !
rozcietrzewiacz

6

หากคุณต้องการพฤติกรรมที่แตกต่างไม่ว่าจะเป็นการเชื่อมโยงที่ขาดหรือวงจรคุณยังสามารถใช้% Y กับการค้นหา:

$ 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

ตัวอย่างนี้จะถูกคัดลอกจากโพสต์นี้ (เว็บไซต์ลบ)

การอ้างอิง


อีกอย่างหนึ่งที่จดชวเลขสำหรับผู้ที่findไม่สนับสนุนคำสั่งนั้นxtypeสามารถได้มาจากสิ่งนี้: find . type l -printf "%Y %p\n" | grep -w '^N'. เมื่อแอนดี้เอาชนะฉันด้วยความคิด (พื้นฐาน) เดียวกันในสคริปต์ของเขาฉันก็ลังเลที่จะเขียนมันเป็นคำตอบแยกต่างหาก :)
syntaxerror

2

ฉันใช้สิ่งนี้กับเคสของฉันและมันใช้งานได้ค่อนข้างดีเพราะฉันรู้จักไดเรกทอรีเพื่อค้นหา symlinks ที่ไม่ทำงาน:

find -L $path -maxdepth 1 -type l

และโฟลเดอร์ของฉันมีลิงค์ไปยัง/usr/shareแต่ก็ไม่ได้เข้าไป ลิงก์ข้ามอุปกรณ์และลิงค์ที่ใช้ได้สำหรับ chroots และอื่น ๆ ยังคงเป็นข้อผิดพลาด แต่สำหรับกรณีการใช้งานของฉันก็เพียงพอแล้ว


2

คำตอบที่ไม่ต้องคิดง่าย ๆ ซึ่งเป็นรูปแบบของเวอร์ชั่นของ OP บางครั้งคุณแค่ต้องการพิมพ์หรือจำง่าย:

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


1

สิ่งนี้จะพิมพ์ชื่อของ symlink ที่เสียหายในไดเรกทอรีปัจจุบัน

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

ทำงานใน Bash ไม่ทราบเกี่ยวกับกระสุนนัดอื่น

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.