ฉันวิ่ง
ln /a/A /b/B
ผมอยากจะเห็นในโฟลเดอร์ที่จุดไฟล์โดยa
ls
ฉันวิ่ง
ln /a/A /b/B
ผมอยากจะเห็นในโฟลเดอร์ที่จุดไฟล์โดยa
ls
คำตอบ:
คุณสามารถค้นหาหมายเลขไอโหนดสำหรับไฟล์ของคุณด้วย
ls -i
และ
ls -l
แสดงจำนวนการอ้างอิง (จำนวนของลิงก์ไปยัง inode เฉพาะ)
หลังจากคุณพบหมายเลขไอโหนดคุณสามารถค้นหาไฟล์ทั้งหมดด้วยไอโหนดเดียวกัน:
find . -inum NUM
จะแสดงชื่อไฟล์สำหรับ inode NUM ใน dir ปัจจุบัน (.)
ไม่มีคำตอบที่ชัดเจนสำหรับคำถามของคุณ ซึ่งแตกต่างจาก symlinks, hardlinks แยกไม่ออกจาก "ไฟล์ต้นฉบับ"
รายการไดเรกทอรีประกอบด้วยชื่อไฟล์และตัวชี้ไปยังไอโหนด inode ในทางกลับกันมีข้อมูลเมตาของไฟล์และ (ตัวชี้ไปที่) เนื้อหาของไฟล์จริง) การสร้างฮาร์ดลิงก์จะสร้างชื่อไฟล์อื่น + อ้างอิงถึงไอโหนดเดียวกัน การอ้างอิงเหล่านี้เป็นแบบทิศทางเดียว (ในระบบไฟล์ทั่วไปอย่างน้อย) - inode จะเก็บการอ้างอิงเท่านั้น ไม่มีวิธีที่แท้จริงในการค้นหาซึ่งเป็นชื่อไฟล์ "ดั้งเดิม"
โดยวิธีการนี้คือเหตุผลที่เรียกระบบที่จะ "ลบ" unlink
ไฟล์ที่เรียกว่า มันเพิ่งลบฮาร์ดลิงก์ออก inode ข้อมูลที่แนบมาจะถูกลบเฉพาะเมื่อจำนวนการอ้างอิงของ inode ลดลงถึง 0
วิธีเดียวที่จะค้นหาการอ้างอิงอื่น ๆ ไปยัง inode ที่กำหนดคือการค้นหาอย่างละเอียดมากกว่าระบบไฟล์การตรวจสอบไฟล์ที่อ้างถึง inode ในคำถาม คุณสามารถใช้ 'ทดสอบ A -ef B' จากเปลือกเพื่อทำการตรวจสอบนี้
UNIX มีฮาร์ดลิงก์และลิงก์สัญลักษณ์ (สร้างด้วย"ln"
และ"ln -s"
ตามลำดับ) ลิงก์สัญลักษณ์เป็นเพียงไฟล์ที่มีเส้นทางจริงไปยังไฟล์อื่นและสามารถข้ามระบบไฟล์ได้
ฮาร์ดลิงก์มีมาตั้งแต่ยุคแรกสุดของ UNIX (ที่ฉันจำได้อยู่แล้วและมันกลับมาอีกซักพัก) พวกเขาเป็นสองรายการไดเรกทอรีที่อ้างอิงข้อมูลพื้นฐานเดียวกันแน่นอน inode
ข้อมูลในแฟ้มที่ระบุไว้โดยตัวของมัน แต่ละไฟล์บนระบบไฟล์ชี้ไปที่ไอโหนด แต่ไม่จำเป็นว่าไฟล์แต่ละไฟล์จะชี้ไปที่ไอโหนดที่ไม่ซ้ำกันนั่นคือที่มาของฮาร์ดลิงก์
เนื่องจาก inodes มีความเฉพาะตัวสำหรับระบบไฟล์ที่กำหนดจึงมีข้อ จำกัด ว่าฮาร์ดลิงก์ต้องอยู่ในระบบไฟล์เดียวกัน (ซึ่งแตกต่างจากลิงก์สัญลักษณ์) โปรดทราบว่าซึ่งแตกต่างจากลิงก์สัญลักษณ์ไม่มีไฟล์ที่มีสิทธิพิเศษ - ไฟล์เหล่านั้นเท่าเทียมกัน พื้นที่ข้อมูลที่จะถูกปล่อยออกมาเมื่อทุกไฟล์โดยใช้ไอโหนดที่ถูกลบ (และกระบวนการทั้งหมดที่ปิดเช่นกัน แต่ที่เป็นปัญหาที่แตกต่างกัน)
คุณสามารถใช้"ls -i"
คำสั่งเพื่อรับ inode ของไฟล์เฉพาะ จากนั้นคุณสามารถใช้"find <filesystemroot> -inum <inode>"
คำสั่งเพื่อค้นหาไฟล์ทั้งหมดบนระบบไฟล์ด้วย inode ที่กำหนด
นี่คือสคริปต์ที่ทำอย่างนั้น คุณเรียกใช้ด้วย:
findhardlinks ~/jquery.js
และจะค้นหาไฟล์ทั้งหมดในระบบไฟล์นั้นซึ่งเป็นลิงค์ยากสำหรับไฟล์นั้น:
pax@daemonspawn:~# ./findhardlinks /home/pax/jquery.js
Processing '/home/pax/jquery.js'
'/home/pax/jquery.js' has inode 5211995 on mount point '/'
/home/common/jquery-1.2.6.min.js
/home/pax/jquery.js
นี่คือสคริปต์
#!/bin/bash
if [[ $# -lt 1 ]] ; then
echo "Usage: findhardlinks <fileOrDirToFindFor> ..."
exit 1
fi
while [[ $# -ge 1 ]] ; do
echo "Processing '$1'"
if [[ ! -r "$1" ]] ; then
echo " '$1' is not accessible"
else
numlinks=$(ls -ld "$1" | awk '{print $2}')
inode=$(ls -id "$1" | awk '{print $1}' | head -1l)
device=$(df "$1" | tail -1l | awk '{print $6}')
echo " '$1' has inode ${inode} on mount point '${device}'"
find ${device} -inum ${inode} 2>/dev/null | sed 's/^/ /'
fi
shift
done
. ./findhardlinks.bash
ขณะที่อยู่ใน Zsh ของ OS X หน้าต่างปัจจุบันของฉันในหน้าจอปิด
INUM=$(stat -c %i $1)
. NUM_LINKS=$(stat -c %h $1)
ด้วย ดูman stat
ตัวแปรรูปแบบเพิ่มเติมที่คุณสามารถใช้ได้
ls -l
คอลัมน์แรกจะแสดงสิทธิ์ คอลัมน์ที่สองจะเป็นจำนวนรายการย่อย (สำหรับไดเรกทอรี) หรือจำนวนเส้นทางไปยังข้อมูลเดียวกัน (ฮาร์ดลิงก์รวมถึงไฟล์ต้นฉบับ) ไปยังไฟล์ เช่น:
-rw-r--r--@ 2 [username] [group] [timestamp] HardLink
-rw-r--r--@ 2 [username] [group] [timestamp] Original
^ Number of hard links to the data
inode
ที่จุดหันไปที่เนื้อหาดิสก์
วิธีการที่ง่ายกว่านี้ต่อไปนี้? (หลังอาจแทนที่สคริปต์ยาวด้านบน!)
หากคุณมีไฟล์เฉพาะ<THEFILENAME>
และต้องการทราบว่าฮาร์ดลิงก์ทั้งหมดกระจายอยู่ในไดเรกทอรี<TARGETDIR>
(ซึ่งอาจเป็นระบบไฟล์ทั้งหมดที่แสดงโดย/
)
find <TARGETDIR> -type f -samefile <THEFILENAME>
ขยายตรรกะถ้าคุณต้องการทราบไฟล์ทั้งหมดในการ<SOURCEDIR>
มีฮาร์ดลิงก์หลายตัวกระจายอยู่<TARGETDIR>
:
find <SOURCEDIR> -type f -links +1 \
-printf "\n\n %n HardLinks of file : %H/%f \n" \
-exec find <TARGETDIR> -type f -samefile {} \;
-type f
เพราะไฟล์สามารถเป็นไดเรกทอรีด้วย
.
และ..
รายการในไดเรกทอรี hardlinks คุณสามารถบอกได้ว่าหลาย subdirs .
อยู่ในไดเรกทอรีจากการนับการเชื่อมโยงของ นี่คือ moot อย่างไรก็ตามเนื่องจากfind -samefile .
ยังไม่พิมพ์subdir/..
ผลลัพธ์ ใด ๆ find
(อย่างน้อยรุ่น GNU) ดูเหมือนว่าจะ hardcoded จะไม่สนใจแม้จะมี..
-noleaf
O(n^2)
และเรียกใช้find
ครั้งเดียวสำหรับสมาชิกแต่ละคนของชุดไฟล์ฮาร์ด ลิงก์ find ... -printf '%16i %p\n' | sort -n | uniq -w 16 --all-repeated=separate
จะทำงาน (16 ไม่กว้างพอสำหรับการแสดงทศนิยม 2 ^ 63-1 ดังนั้นเมื่อ XFS ระบบแฟ้มของคุณมีขนาดใหญ่พอที่จะมีหมายเลขไอโหนดที่สูงระวัง)
มีคำตอบมากมายสำหรับสคริปต์ในการค้นหาลิงก์ทั้งหมดในระบบไฟล์ พวกเขาส่วนใหญ่ทำสิ่งที่งี่เง่าเช่นการเรียกใช้การค้นหาเพื่อสแกนระบบไฟล์ทั้งหมดเพื่อ-samefile
หาไฟล์ที่ถูกเชื่อมโยงหลายครั้งของ EACH มันบ้าไปแล้ว; สิ่งที่คุณต้องมีก็คือเรียงลำดับหมายเลขไอโหนดและพิมพ์ซ้ำ
ด้วยการส่งผ่านระบบไฟล์เพียงครั้งเดียวเพื่อค้นหาและจัดกลุ่มไฟล์ฮาร์ดลิงก์ทั้งหมด
find dirs -xdev \! -type d -links +1 -printf '%20D %20i %p\n' |
sort -n | uniq -w 42 --all-repeated=separate
นี่เร็วกว่าคำตอบอื่น ๆในการค้นหาไฟล์ฮาร์ดลิงก์หลายชุด
find /foo -samefile /bar
ดีมากสำหรับไฟล์เดียว
-xdev
: จำกัด ระบบไฟล์เดียว ไม่จำเป็นอย่างเคร่งครัดเนื่องจากเราพิมพ์ FS-id เป็น uniq ด้วย! -type d
ปฏิเสธไดเรกทอรี: .
และ..
รายการหมายถึงพวกเขาเชื่อมโยงอยู่เสมอ-links +1
: นับลิงค์อย่างเคร่งครัด > 1
-printf ...
พิมพ์ FS-id, หมายเลขไอโหนดและพา ธ (ด้วยการขยายไปยังความกว้างคอลัมน์คงที่ที่เราสามารถบอกuniq
ได้)sort -n | uniq ...
การเรียงลำดับตัวเลขและไม่ซ้ำกันใน 42 คอลัมน์แรกโดยแยกกลุ่มด้วยบรรทัดว่างการใช้! -type d -links +1
หมายความว่าอินพุตเรียงลำดับมีขนาดใหญ่เท่ากับเอาต์พุตสุดท้ายของ uniq เท่านั้นดังนั้นเราจึงไม่ได้ทำการเรียงลำดับสตริงจำนวนมาก นอกจากว่าคุณจะรันในไดเรกทอรีย่อยที่มีเพียงหนึ่งในชุดของลิงก์ อย่างไรก็ตามจะใช้เวลา CPU น้อยลงในการข้ามระบบไฟล์มากกว่าโซลูชันที่โพสต์อื่น ๆ
ตัวอย่างผลลัพธ์:
...
2429 76732484 /home/peter/weird-filenames/test/.hiddendir/foo bar
2429 76732484 /home/peter/weird-filenames/test.orig/.hiddendir/foo bar
2430 17961006 /usr/bin/pkg-config.real
2430 17961006 /usr/bin/x86_64-pc-linux-gnu-pkg-config
2430 36646920 /usr/lib/i386-linux-gnu/dri/i915_dri.so
2430 36646920 /usr/lib/i386-linux-gnu/dri/i965_dri.so
2430 36646920 /usr/lib/i386-linux-gnu/dri/nouveau_vieux_dri.so
2430 36646920 /usr/lib/i386-linux-gnu/dri/r200_dri.so
2430 36646920 /usr/lib/i386-linux-gnu/dri/radeon_dri.so
...
สิ่งที่ต้องทำ ?: ยกเลิกแผ่นส่งออกที่มีหรือ awk
มีการสนับสนุนการเลือกข้อมูลที่ จำกัด อย่างมากดังนั้นฉันจึงเลือกเอาท์พุท find และใช้ความกว้างคงที่ 20chars กว้างพอสำหรับ inode สูงสุดหรือหมายเลขอุปกรณ์ (2 ^ 64-1 = 18446744073709551615) XFS เลือกหมายเลขไอโหนดตามตำแหน่งที่ดิสก์ถูกจัดสรรไม่ใช่ต่อเนื่องกันตั้งแต่ 0 ดังนั้นระบบไฟล์ XFS ขนาดใหญ่จึงสามารถมีหมายเลข inode> 32 บิตได้แม้ว่าจะไม่มีไฟล์หลายพันล้านไฟล์ก็ตาม ระบบไฟล์อื่นอาจมีหมายเลขไอโหนด 20 หลักแม้ว่าจะไม่ใหญ่โตก็ตามcut
uniq
สิ่งที่ต้องทำ: เรียงลำดับกลุ่มของรายการที่ซ้ำกันตามเส้นทาง ให้เรียงลำดับตามจุดเชื่อมต่อจากนั้นหมายเลขไอโหนดจะรวมสิ่งต่าง ๆ เข้าด้วยกันหากคุณมีหลายส่วนย่อยที่มีฮาร์ดลิงก์จำนวนมาก (เช่นกลุ่มของกลุ่มสองกลุ่มทำงานร่วมกัน แต่เอาท์พุทผสมกัน)
สุดท้ายsort -k 3
จะเรียงลำดับบรรทัดแยกกันไม่ใช่กลุ่มของบรรทัดเป็นระเบียนเดียว sort --zero-terminated -k 3
การประมวลผลล่วงหน้าด้วยบางสิ่งบางอย่างเพื่อแปลงคู่บรรทัดใหม่เป็นไบต์ NUL และการใช้ GNU อาจทำเคล็ดลับได้ tr
ใช้งานได้กับอักขระเดี่ยวเท่านั้นไม่ใช่ 2-> 1 หรือ 1-> 2 รูปแบบ perl
จะทำมัน (หรือเพียงแค่แยกและจัดเรียงภายใน Perl หรือ awk) sed
อาจใช้งานได้
%D
เป็นตัวระบุระบบไฟล์ (เป็นค่าเฉพาะสำหรับการบู๊ตปัจจุบันในขณะที่ไม่มีระบบไฟล์umount
ed) ดังนั้นการติดตามต่อไปนี้จะเป็นเรื่องทั่วไปมากกว่า: find directories.. -xdev ! -type d -links +1 -printf '%20i %20D %p\n' | sort -n | uniq -w 42 --all-repeated=separate
. ใช้งานได้นานหากไม่มีไดเรกทอรีที่ระบุมีไดเรกทอรีอื่นในระดับระบบแฟ้มรวมถึงดูทุกสิ่งที่สามารถเชื่อมโยงได้ (เช่นอุปกรณ์หรือซอฟต์ลิงค์ - ใช่ซอฟต์ลิงค์สามารถนับลิงค์ได้มากกว่า 1) โปรดทราบว่าdev_t
และino_t
วันนี้มีความยาว 64 บิต สิ่งนี้น่าจะมีอยู่ตราบใดที่เรามีระบบ 64 บิต
! -type d
-type f
ฉันยังมี symlink ที่ฮาร์ดลิงก์บางตัวในระบบไฟล์ของฉันจากการจัดระเบียบกลุ่มของไฟล์ Updated ตอบของฉันกับรุ่นปรับปรุงของคุณ ( แต่ผมใส่ FS-ID แรกดังนั้นการเรียงลำดับในกลุ่มน้อยโดยระบบแฟ้ม.)
นี่เป็นข้อคิดเห็นบางอย่างสำหรับคำตอบและสคริปต์ของ Torocoro-Macho แต่เห็นได้ชัดว่ามันไม่เหมาะสมในช่องแสดงความคิดเห็น
เขียนสคริปต์ของคุณใหม่ด้วยวิธีการที่ตรงไปตรงมามากขึ้นในการค้นหาข้อมูลและทำให้การเรียกใช้กระบวนการน้อยลง
#!/bin/sh
xPATH=$(readlink -f -- "${1}")
for xFILE in "${xPATH}"/*; do
[ -d "${xFILE}" ] && continue
[ ! -r "${xFILE}" ] && printf '"%s" is not readable.\n' "${xFILE}" 1>&2 && continue
nLINKS=$(stat -c%h "${xFILE}")
if [ ${nLINKS} -gt 1 ]; then
iNODE=$(stat -c%i "${xFILE}")
xDEVICE=$(stat -c%m "${xFILE}")
printf '\nItem: %s[%d] = %s\n' "${xDEVICE}" "${iNODE}" "${xFILE}";
find "${xDEVICE}" -inum ${iNODE} -not -path "${xFILE}" -printf ' -> %p\n' 2>/dev/null
fi
done
ฉันพยายามทำให้มันคล้ายกับของคุณมากที่สุดเพื่อการเปรียบเทียบที่ง่าย
เราควรหลีกเลี่ยง$IFS
เวทย์มนตร์เสมอหากมี glob พอเพราะมันซับซ้อนโดยไม่จำเป็นและชื่อไฟล์จริงสามารถมีการขึ้นบรรทัดใหม่ (แต่ในทางปฏิบัติส่วนใหญ่เหตุผลแรก)
คุณควรหลีกเลี่ยงการวิเคราะห์คำด้วยตนเองls
และออกมากที่สุดเท่าที่จะเป็นไปได้เพราะมันจะกัดคุณไม่ช้าก็เร็ว ตัวอย่างเช่น: ในawk
บรรทัดแรกของคุณคุณล้มเหลวในทุกชื่อไฟล์ที่มีช่องว่าง
printf
มักจะบันทึกปัญหาในที่สุดเนื่องจากมีความแข็งแกร่งกับ%s
ไวยากรณ์ นอกจากนี้ยังให้คุณควบคุมการแสดงผลได้อย่างเต็มที่และสอดคล้องกับทุกระบบไม่เหมือนecho
กัน
stat
สามารถช่วยคุณประหยัดได้มากในกรณีนี้
GNU find
มีพลัง
คุณhead
และtail
การร้องขอสามารถจัดการได้โดยตรงawk
กับเช่นexit
คำสั่งและ / หรือการเลือกNR
ตัวแปร สิ่งนี้จะบันทึกขั้นตอนการร้องขอซึ่งนักพนันส่วนใหญ่มักทำงานหนักในสคริปต์ที่ทำงานหนัก
คุณegrep
s grep
สามารถก็เช่นกันจะเป็นเพียงแค่
find ... -xdev -type f -links +1 -printf '%16i %p\n' | sort -n | uniq -w 16 --all-repeated=separate
การใช้งาน นี่คือเร็วกว่ามากเนื่องจากมันเคลื่อนที่ผ่าน fs เพียงครั้งเดียว สำหรับหลาย FS พร้อมกันคุณจะต้องใส่หมายเลข inode ด้วยรหัส FS อาจจะด้วยfind -exec stat... -printf ...
ตามfindhardlinks
สคริปต์ (เปลี่ยนชื่อเป็นhard-links
) นี่คือสิ่งที่ฉันได้รับการปรับโครงสร้างใหม่และทำให้ใช้งานได้
เอาท์พุท:
# ./hard-links /root
Item: /[10145] = /root/.profile
-> /proc/907/sched
-> /<some-where>/.profile
Item: /[10144] = /root/.tested
-> /proc/907/limits
-> /<some-where else>/.bashrc
-> /root/.testlnk
Item: /[10144] = /root/.testlnk
-> /proc/907/limits
-> /<another-place else>/.bashrc
-> /root/.tested
# cat ./hard-links
#!/bin/bash
oIFS="${IFS}"; IFS=$'\n';
xPATH="${1}";
xFILES="`ls -al ${xPATH}|egrep "^-"|awk '{print $9}'`";
for xFILE in ${xFILES[@]}; do
xITEM="${xPATH}/${xFILE}";
if [[ ! -r "${xITEM}" ]] ; then
echo "Path: '${xITEM}' is not accessible! ";
else
nLINKS=$(ls -ld "${xITEM}" | awk '{print $2}')
if [ ${nLINKS} -gt 1 ]; then
iNODE=$(ls -id "${xITEM}" | awk '{print $1}' | head -1l)
xDEVICE=$(df "${xITEM}" | tail -1l | awk '{print $6}')
echo -e "\nItem: ${xDEVICE}[$iNODE] = ${xITEM}";
find ${xDEVICE} -inum ${iNODE} 2>/dev/null|egrep -v "${xITEM}"|sed 's/^/ -> /';
fi
fi
done
IFS="${oIFS}"; echo "";
โซลูชัน GUI ใกล้กับคำถามของคุณจริง ๆ :
คุณไม่สามารถแสดงรายการไฟล์ฮาร์ดลิงก์ที่เกิดขึ้นจริงจาก "ls" เพราะเนื่องจากผู้วิจารณ์ก่อนหน้าได้ชี้ให้เห็นว่าไฟล์ "ชื่อ" เป็นเพียงนามแฝงกับข้อมูลเดียวกัน อย่างไรก็ตามมีเครื่องมือ GUI ที่ใกล้เคียงกับสิ่งที่คุณต้องการจริงๆคือการแสดงรายการพา ธ ของชื่อไฟล์ที่ชี้ไปที่ข้อมูลเดียวกัน (เป็นฮาร์ดลิงก์) ภายใต้ลินุกซ์เรียกว่า FSLint ตัวเลือกที่คุณต้องการอยู่ภายใต้ "ชื่อ clashes" -> ยกเลิกการเลือก "$ PATH" ในการค้นหา (XX) -> และเลือก "นามแฝง" จากช่องแบบเลื่อนลงหลังจาก "for ... " ไปยังกึ่งกลางด้านบน
FSLint มีเอกสารไม่ดีมาก แต่ฉันพบว่าทำให้แน่ใจว่าไดเรกทอรีต้นไม้ที่ จำกัด ภายใต้ "เส้นทางการค้นหา" ด้วยช่องทำเครื่องหมายที่เลือกสำหรับ "เรียกคืนหรือไม่" และตัวเลือกข้างต้นการแสดงรายการของข้อมูลฮาร์ดลิงก์ที่มีพา ธ และชื่อที่ "ชี้" ไปยังข้อมูลเดียวกันจะถูกสร้างขึ้นหลังจากโปรแกรมค้นหา
คุณสามารถกำหนดค่าls
เพื่อเน้นการเชื่อมโยงโดยใช้ 'นามแฝง' แต่ตามที่ระบุไว้ก่อนหน้านี้ไม่มีวิธีแสดง 'แหล่งที่มา' ของการเชื่อมโยงซึ่งเป็นสาเหตุที่ฉันผนวก.hardlink
เพื่อช่วย
เพิ่มสิ่งต่อไปนี้ในของคุณ .bashrc
alias ll='LC_COLLATE=C LS_COLORS="$LS_COLORS:mh=1;37" ls -lA --si --group-directories-first'
link(2)
เรียกใช้ระบบจะไม่มีความหมายในสิ่งที่เป็นต้นฉบับและอีกอันคือการเชื่อมโยงfind / -samefile /a/A
นี่คือเหตุผลที่เป็นคำตอบชี้ให้เห็นวิธีเดียวที่จะพบการเชื่อมโยงทั้งหมด เนื่องจากรายการไดเรกทอรีหนึ่งสำหรับ inode ไม่ได้ "รู้เกี่ยวกับ" รายการไดเรกทอรีอื่น ๆ ของ inode เดียวกัน ทั้งหมดที่พวกเขาทำคือ refcount inodeunlink(2)ed
เพื่อที่จะสามารถถูกลบเมื่อนามสกุลเพราะมันเป็น (นี่คือ "จำนวนลิงค์" ในls
ผลลัพธ์)