การพิจารณาว่าไฟล์เป็นฮาร์ดลิงก์หรือลิงก์สัญลักษณ์?


51

ฉันกำลังสร้างเชลล์สคริปต์ที่จะนำชื่อไฟล์ / พา ธ ไปยังไฟล์และตรวจสอบว่าไฟล์นั้นเป็นลิงก์สัญลักษณ์หรือฮาร์ดลิงก์

สิ่งเดียวคือฉันไม่ทราบวิธีการดูว่าพวกเขาเป็นลิงค์ยาก ฉันสร้างไฟล์ 2 ไฟล์หนึ่งไฟล์เป็นฮาร์ดลิงก์และอีกหนึ่งลิงก์สัญลักษณ์เพื่อใช้เป็นไฟล์ทดสอบ แต่ฉันจะทราบได้อย่างไรว่าไฟล์เป็นฮาร์ดลิงก์หรือสัญลักษณ์ภายในเชลล์สคริปต์

นอกจากนี้ฉันจะค้นหาพาร์ติชันปลายทางของลิงก์สัญลักษณ์ได้อย่างไร สมมุติว่าฉันมีไฟล์ที่เชื่อมโยงไปยังพาร์ติชันอื่นฉันจะค้นหาพา ธ ไปยังไฟล์ต้นฉบับนั้นได้อย่างไร


16
คุณหมายถึงอะไรโดยการเชื่อมโยงอย่างหนัก? ไฟล์ทั้งหมดเป็นลิงค์ที่ยาก
terdon

1
@terdon ln /foo/bar/ /foo/bar2สร้าง hardlink ในขณะที่ln -s /foo/bar /foo/bar2สร้าง symlink นั่นหมายความว่าอะไร
DisplayName

14
@DisplayName ใช่ แต่ไฟล์ทั้งหมดเป็นฮาร์ดลิงก์ไปยัง inode นั่นเป็นวิธีที่ระบบไฟล์ Linux ทำงาน ในตัวอย่างของคุณbar2และbarเป็นทั้งฮาร์ดลิงก์เพียงแค่ชี้ไปที่ไอโหนดเดียวกัน
terdon

10
@DisplayName ใช่พวกเขามีการเชื่อมโยงอื่น ๆ ยากที่จะinodes ไม่มีความขัดแย้งที่นี่ ไฟล์คือลิงค์ไปยัง inode นั่นคือคำจำกัดความของไฟล์ ในกรณีของคุณคุณมีลิงค์เหล่านี้ในสถานที่ต่าง ๆ แต่นั่นไม่ได้เปลี่ยนโครงสร้างข้อมูลพื้นฐาน ประเด็นของฉันคือทั้งสองbarและbar2มีความสำคัญเท่าเทียมกัน หนึ่งไม่ได้เชื่อมโยงไปยังอีกพวกเขาทั้งสองเชื่อมโยง แต่ชี้ไปที่ไอโหนดเดียวกัน
terdon

3
@Scott ไม่ฉันกำลังบอกว่าไฟล์ปกติเป็นฮาร์ดลิงก์และฮาร์ดลิงก์ที่สร้างโดยlnไม่แตกต่างจากไฟล์ทั่วไป
terdon

คำตอบ:


42

คำตอบของจิมอธิบายถึงวิธีการในการทดสอบสำหรับ symlink A: โดยใช้test's -Lทดสอบ

แต่การทดสอบสำหรับ "ฮาร์ดลิงก์" ก็คือการพูดอย่างเคร่งครัดไม่ใช่สิ่งที่คุณต้องการ ฮาร์ดลิงก์ทำงานได้เนื่องจากวิธีที่ Unix จัดการกับไฟล์: แต่ละไฟล์ถูกแสดงด้วยไอโหนดเดียว จากนั้นไอโหนดเดียวจะมีชื่อหรือรายการไดเรกทอรีเป็นศูนย์หรือมากกว่านั้นหรือโดยทางเทคนิคแล้วฮาร์ดลิงก์ (สิ่งที่คุณเรียกว่า "ไฟล์")

โชคดีที่statคำสั่งมีอยู่สามารถบอกคุณได้ว่าชื่อ inode มีกี่ชื่อ

ดังนั้นคุณกำลังมองหาบางสิ่งเช่นนี้ (ที่นี่สมมติว่ามีการนำ GNU หรือ busybox มาใช้stat):

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

-c '%h'บิตบอกstatเพียงแค่การส่งออกจำนวนของ hardlinks เพื่อ inode คือจำนวนของชื่อไฟล์มี -gt 1จากนั้นตรวจสอบว่ามากกว่า 1 หรือไม่

โปรดทราบว่า symlink เหมือนกับไฟล์อื่น ๆ สามารถเชื่อมโยงไปยังไดเรกทอรีต่าง ๆ ได้ดังนั้นคุณจึงสามารถมีหลายลิงก์ไปยัง symlink เดียว


ตกลงเพื่อให้ชัดเจนฉันสามารถส่งออกจำนวนฮาร์ดลิงก์ที่ไฟล์มีการใช้คำสั่ง stat และถ้ามันมากกว่า 1 แล้วก็มีไฟล์อื่นที่เชื่อมโยงบางแห่งในพาร์ทิชัน
k-Rocker

@ k-Rocker ใช่ จากนั้นจะมีชื่อที่สองที่ใดที่หนึ่งบนพาร์ติชัน
Derobert

1
บน OS X หรือ * BSD stat -f %l /path/to/fileก็ คุณสามารถใช้gstat -c %h /path/to/fileถ้าคุณมี coreutils GNU ติดตั้งโดยไม่มีชื่อเริ่มต้น (ด้วย Homebrew บน OS X)
GDP2

29

ตัวอย่าง:

$ 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

รายการf1, f2และf3ไดเรกทอรีเป็นไฟล์เดียวกัน (inode เดียวกัน: 10802124, คุณจะสังเกตเห็นว่าจำนวนลิงค์คือ 3) มันเป็นการเชื่อมโยงอย่างหนักไปยังไฟล์ปกติเดียวกัน

s4และs5เป็นไฟล์เดียวกัน (10802384) พวกเขาเป็นประเภทsymlinkไม่ปกติ s3พวกเขาชี้ไปยังเส้นทางที่นี่ เนื่องจากs4และs5เป็นรายการของไดเรกทอรีเดียวกันพา ธ สัมพัทธ์s3นั้นจะชี้ไปที่ไฟล์เดียวกัน (อันที่มี inod 10802347) สำหรับทั้งคู่

หากคุณทำเช่นls -Llนั้นนั่นคือการขอให้รับข้อมูลไฟล์หลังจากการแก้ไข symlink:

$ 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

คุณจะพบว่าพวกเขาทั้งหมดแก้ไขไฟล์เดียวกัน (10802124)

คุณสามารถตรวจสอบว่าไฟล์เป็น symlink ด้วย[ -L file ]หรือไม่ ในทำนองเดียวกันคุณสามารถทดสอบว่าไฟล์เป็นไฟล์ปกติด้วย[ -f file ]หรือไม่ แต่ในกรณีนั้นการตรวจสอบจะทำหลังจากแก้ไข symlink แล้ว

ฮาร์ดลิงก์ไม่ใช่ประเภทของไฟล์ แต่เป็นชื่อที่แตกต่างกันสำหรับไฟล์ (ทุกประเภท)


19

การใช้-hและ-Lโอเปอเรเตอร์ของtestคำสั่ง:

-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

ตามเธรด SO นี้พวกเขามีพฤติกรรมเหมือนกัน แต่-Lเป็นที่ต้องการ


ตกลงเยี่ยม แต่สิ่งที่เกี่ยวกับการเชื่อมโยงอย่างหนัก? ฉันตรวจสอบดอกยางแล้ว แต่ไม่มีอะไรเกี่ยวข้องกับฮาร์ดลิงก์ ถ้า -L ส่งคืนค่าเท็จนั่นหมายความว่าเป็นลิงก์ที่ยากหรือไม่ หรือเพียงแค่ไฟล์ปกติ?
k-Rocker

1
inodeเชื่อมโยงอย่างหนักแบ่งปันเดียวกัน นอกจากนี้การเชื่อมโยงนุ่มแสดงlที่จุดเริ่มต้นของการของls -lการส่งออก ... ฉันคิดว่าคุณอาจจะสามารถที่จะนำกฎเหล่านั้นเข้าด้วยกันในสคริปต์รวมทั้ง[[ -L file ]]การทดสอบเพื่อดูว่าไฟล์ที่กำหนดเป็นทั้งนุ่มหรือยาก
jimm-cl

ตกลงฉันจะหาพาร์ทิชันปลายทางของลิงค์สัญลักษณ์ได้อย่างไร
k-Rocker

3

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

หากคุณกำลังอ่านสิ่งนี้ทั้งหมดและคุณพบว่าเกิดอะไรขึ้นคุณก็เป็นคนดี คุณไม่จำเป็นต้องอ่านตัวฉันสักหน่อย หากคุณยังสับสนอยู่ให้ไปต่อ

คำตอบสั้น ๆ จริง ๆ คือการเชื่อมโยงที่ยากไม่ใช่การเชื่อมโยงทั้งหมดไม่ใช่ในลักษณะการเชื่อมโยงสัญลักษณ์ มันเป็นรายการใหม่ในโครงสร้างไดเรกทอรีที่ชี้ไปยังจำนวนไบต์เดียวกันกับที่รายการไดเรกทอรีดั้งเดิมทำและเมื่อคุณสร้างมันขึ้นมาแล้วมันก็เหมือนกับ 'จริง' และถูกต้องตามกฎหมายเป็นรายการแรก ไฟล์ 'ปกติ' ทุกไฟล์ในไดรฟ์ของคุณมีฮาร์ดลิงก์อย่างน้อยหนึ่งลิงก์ หากปราศจากสิ่งนั้นคุณจะไม่เห็นสิ่งใดเลยไดเรกทอรีและจะไม่สามารถอ้างถึงหรือใช้งานได้ ดังนั้นหากคุณมีไฟล์ Fred.txt และคุณเชื่อมโยงอย่างหนักกับ Wilma.txt และ Barney.txt ทั้งสามชื่อ (และรายการไดเรกทอรี) จะอ้างถึงไฟล์เดียวกันและพวกมันก็ใช้ได้อย่างเท่าเทียมกัน ไม่มีวิธีใดที่ระบบปฏิบัติการจะบอกได้ว่ารายการใดรายการหนึ่งถูกสร้างขึ้นเมื่อคุณกด "บันทึก" ในเท็กซ์เอดิเตอร์ของคุณและรายการอื่น ๆ ถูกสร้างด้วยคำสั่ง "ln"

ระบบปฏิบัติการจะต้องติดตามจำนวนรายการต่าง ๆ ที่ชี้ไปยังไฟล์เดียวกัน หากคุณลบ Wilma.txt ไม่แปลกใจเลยที่คุณจะไม่เพิ่มที่ว่างในไดรฟ์ แต่ถ้าคุณลบ Fred.txt (ไฟล์ 'ดั้งเดิม') คุณจะยังไม่เพิ่มพื้นที่ว่างในไดรฟ์ของคุณเนื่องจากข้อมูลในไดรฟ์ที่รู้จักกันในชื่อ Fred.txt นั้นยังคงเป็น Barney.txt เฉพาะเมื่อคุณลบทั้งหมดของรายการไดเรกทอรีจะ OS เดจัดสรรพื้นที่ที่ข้อมูลที่ตัวเองได้รับการครอบครอง

หาก Barney.txt เป็นลิงก์แบบสัญลักษณ์การลบ Fred.txt จะเป็นการยกเลิกการจัดสรรพื้นที่และ Barney.txt จะเป็นลิงก์ที่เสีย นอกจากนี้หากคุณย้ายหรือเปลี่ยนชื่อไฟล์ที่มีลิงก์สัญลักษณ์ซึ่งชี้ไปที่ไฟล์นั้นคุณจะทำลายลิงก์ แต่คุณสามารถย้ายหรือเปลี่ยนชื่อไฟล์ฮาร์ดลิงก์ทั้งหมดที่คุณต้องการโดยไม่ต้องทำลายรายการไดเรกทอรีอื่นที่ชี้ไปที่ไฟล์ / ข้อมูลนั้นเพราะทั้งหมดนั้นเป็นรายการไดเรกทอรีที่อ้างถึงบล็อกข้อมูลบนไดรฟ์เดียวกัน (โดยใช้ inode # ของข้อมูลนั้น)

[อีกสองปีต่อมาและสุดท้ายก็ทำให้ฉันสับสนสักครู่หนึ่งดังนั้นฉันคิดว่าฉันจะชี้แจง หากคุณพิมพ์ "mv ./Wilma.txt ../elswhere/Betty.txt" ดูเหมือนว่าคุณกำลังย้ายไฟล์ แต่ที่จริงแล้วคุณไม่ใช่ สิ่งที่คุณกำลังทำอยู่จริงๆคือการลบรายการโฆษณาออกจากรายการไดเรกทอรีของไดเรกทอรีปัจจุบันของคุณรายการที่ระบุว่า "ชื่อ 'Wilma.txt' นั้นเชื่อมโยงกับข้อมูลที่สามารถพบได้โดยใช้ inode ###### #, "และเพิ่มรายการโฆษณาใหม่ลงในรายการไดเรกทอรีของไดเรกทอรี ../elshere ที่ระบุว่า" ชื่อ 'Betty.txt' นั้นเชื่อมโยงกับข้อมูลที่สามารถพบได้ผ่าน inode ######## " นี่คือเหตุผลที่คุณสามารถ 'ย้าย' ไฟล์ 2 กิกะไบต์ได้เร็วเท่ากับไฟล์ 2 กิโลไบต์ตราบใดที่คุณย้ายพวกมันไปยังตำแหน่งอื่นบนไดรฟ์เดียวกัน]

เนื่องจากระบบปฏิบัติการต้องติดตามจำนวนรายการไดเรกทอรีที่แตกต่างกันที่ชี้ไปยังกลุ่มข้อมูลเดียวกันคุณสามารถบอกได้ว่าไฟล์ใดไฟล์หนึ่งมีการเชื่อมโยงอย่างหนักถึงแม้ว่าคุณจะไม่สามารถบอกได้อย่างชัดเจนว่ารายการไดเรกทอรีที่คุณ กำลังดูอยู่ว่าเป็น 'ดั้งเดิม' อย่างใดอย่างหนึ่งหรือไม่ วิธีหนึ่งคือคำสั่ง "ls" โดยเฉพาะ "ls -l" (นั่นคือ L ตัวพิมพ์เล็กหลังจากเส้นประ)

เพื่อขอยืมตัวอย่างก่อนหน้านี้ ....

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

ตัวอักษรตัวแรกเป็นเส้นประดังนั้นจึงไม่ใช่ไดเรกทอรีหรืออย่างอื่นที่แปลกใหม่มันเป็นไฟล์ธรรมดา 'ปกติ' แต่ถ้ามันเป็นเรื่องธรรมดาจริง ๆ ตัวเลขนั้นหลังจากส่วน rwx-ish จะเป็น "1" ดังเช่นใน "มีรายการไดเรกทอรีหนึ่งรายการที่ชี้ไปยังบล็อกข้อมูลนี้" แต่มันเป็นส่วนหนึ่งของการสาธิตการเชื่อมโยงอย่างหนักดังนั้นแทนที่จะบอกว่า "3"

โปรดทราบว่าสิ่งนี้อาจนำไปสู่พฤติกรรมที่แปลกและลึกลับได้ (หากคุณไม่ได้คาดหัวกับลิงก์ที่ยากนั่นก็คือ) หากคุณเปิด Fred.txt ในโปรแกรมแก้ไขข้อความและทำการเปลี่ยนแปลงคุณจะเห็นการเปลี่ยนแปลงเดียวกันใน Wilma.txt และ Barney.txt หรือไม่ อาจจะ. อาจ. หากโปรแกรมแก้ไขข้อความของคุณบันทึกการเปลี่ยนแปลงโดยการเปิดไฟล์ต้นฉบับและเขียนการเปลี่ยนแปลงไปแล้วใช่ทั้งสามชื่อจะยังคงชี้ไปที่ข้อความเดียวกัน (เพิ่งเปลี่ยนใหม่) แต่หากตัวแก้ไขข้อความของคุณสร้างไฟล์ใหม่ (Fred-new-temp.txt) ให้เขียนเวอร์ชันที่คุณเปลี่ยนไปแล้วลบ Fred.txt จากนั้นเปลี่ยนชื่อ Fred-new-temp.txt เป็น Fred.txt, Wilma และ Barney จะ ยังคงชี้ไปที่เวอร์ชันดั้งเดิมไม่ใช่เวอร์ชันที่เปลี่ยนแปลงใหม่ หากคุณไม่เข้าใจลิงก์ที่ยากอาจทำให้คุณโมโหเล็กน้อย :) [โอเคฉันไม่รู้จริง ๆ เป็นการส่วนตัวเครื่องมือแก้ไขข้อความที่จะทำสิ่งที่เป็นไฟล์ / เปลี่ยนชื่อใหม่ แต่ฉันรู้ว่ามีโปรแกรมอื่น ๆ อีกมากมายที่ทำสิ่งนั้นอย่างแน่นอนดังนั้นโปรดระวัง]

หมายเหตุสุดท้าย: สิ่งใดสิ่งหนึ่งที่ 'fsck' (ตรวจสอบระบบไฟล์) จะตรวจสอบว่ามีบล็อกข้อมูลในไดรฟ์ของคุณหรือไม่ซึ่งไม่ได้อ้างอิงโดยรายการไดเรกทอรีใด ๆ อีกต่อไป บางครั้งมีข้อผิดพลาดและรายการไดเรกทอรีเดียวที่ชี้ไปที่ไอโหนดจะถูกลบ แต่พื้นที่ไดรฟ์เองไม่ได้รับการทำเครื่องหมายว่า "พร้อมใช้งาน" ดังนั้นหนึ่งในงานของ fsck คือการจับคู่พื้นที่ที่จัดสรรทั้งหมดกับรายการไดเรกทอรีทั้งหมดเพื่อให้แน่ใจว่าไม่มีไฟล์ที่ไม่มีการอ้างอิง หากพบบางรายการจะสร้างรายการไดเรกทอรีใหม่และวางไว้ใน "lost + found"


เพียงแค่สงสัยว่า "โปรแกรมอื่น ๆ ที่ทำสิ่งนั้น" คืออะไร
phk

@phk ไม่รู้ว่าเขาคิดอย่างไรโดยเฉพาะ แต่นั่นเป็นวิธีการทั่วไปที่เพียงพอในการทำสิ่งต่าง ๆ ซึ่งอาจใช้เวลานานและจะทำให้คุณอยู่ในสภาวะที่ไม่แน่นอนหากล้มเหลว ตัวอย่างเช่นหากคุณพยายามดาวน์โหลดจากเซิร์ฟเวอร์ระยะไกลและคุณรู้ว่ามีโอกาสที่เซิร์ฟเวอร์อาจหมดเวลาวิธีการหนึ่งก็คือการดาวน์โหลดเนื้อหาทั้งหมดไปยังไฟล์ชั่วคราว ด้วยวิธีนี้หากมีสิ่งผิดปกติเกิดขึ้นกับการดาวน์โหลดคุณยังคงมีไฟล์ต้นฉบับอยู่
cwallenpoole

โปรแกรมเดียวที่ฉันรู้สำหรับบางคนคือ FreeHand เพราะถ้า / เมื่อเกิดข้อผิดพลาดในระหว่างการบันทึกมีไฟล์ชั่วคราวที่ถูกทิ้งไว้แทนที่จะเป็นไฟล์ต้นฉบับที่ยุ่งเหยิง แต่ฉันเคยเห็นโปรแกรมอื่นทำเช่นกัน; ฉันไม่สามารถให้ตัวอย่างเฉพาะกับคุณได้ในขณะนี้
Snarke

2

readlink FILE; echo $?คุณสามารถใช้ สิ่งนี้จะคืนค่า 1 เมื่อเป็นฮาร์ดลิงก์และ 0 เมื่อเป็น symlink

จากหน้า man: "เมื่อเรียกใช้เป็น readlink จะมีการพิมพ์เฉพาะเป้าหมายของลิงก์สัญลักษณ์เท่านั้นหากการให้ที่ระบุไม่ใช่ลิงก์สัญลักษณ์ symbol readlink จะพิมพ์ออกมาโดยไม่มีข้อผิดพลาด"

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