ฉันจะตรวจสอบว่า/my/dir
อยู่บนพาร์ติชันเดียวกันได้/
หรือไม่?
นี่สำหรับการรวมภายในสคริปต์ การเชื่อมต่อแบบผูกควรได้รับการจัดการอย่างถูกต้อง ยินดีต้อนรับโซลูชันที่รองรับ POSIX
ฉันจะตรวจสอบว่า/my/dir
อยู่บนพาร์ติชันเดียวกันได้/
หรือไม่?
นี่สำหรับการรวมภายในสคริปต์ การเชื่อมต่อแบบผูกควรได้รับการจัดการอย่างถูกต้อง ยินดีต้อนรับโซลูชันที่รองรับ POSIX
คำตอบ:
คำสั่งต่อไปนี้ให้ชื่อเฉพาะสำหรับจุดเมานท์ที่มีไฟล์$file
:
df -P -- "$file" | awk 'NR==2 {print $1}'
สิ่งนี้ใช้ได้กับระบบPOSIXใด ๆ -P
ตัวเลือกการกำหนดรูปแบบที่คาดเดาได้; ฟิลด์แรกของบรรทัดที่สองคือ“ ชื่อระบบไฟล์” ดังนั้นในการตรวจสอบสองไฟล์นั้นอยู่ภายใต้จุดเมานท์เดียวกัน:
if [ "$(df -P -- "$file1" | awk 'NR==2 {print $1}')" = \
"$(df -P -- "$file2" | awk 'NR==2 {print $1}')" ]; then
echo "$file1 and $file2 are on the same filesystem" ; fi
หรือหากต้องการบันทึกการเรียกใช้กระบวนการสองสามรายการ:
if df -P -- "$file1" "$file2" |
awk 'NR!=1 {dev[NR] = $1} END {exit(dev[2] != dev[3])}'; then
echo "$file1 and $file2 are on the same filesystem" ; fi
ระบบปฏิบัติการบางระบบสามารถมีช่องว่างในชื่อโวลุ่ม ไม่มีวิธีที่เชื่อถือได้อย่างสมบูรณ์ในการแยกวิเคราะห์df
ผลลัพธ์ในกรณีนี้
ภายใต้ประทุนคุณสามารถระบุระบบแฟ้มที่มีไฟล์โดยที่ข้อมูลที่ส่งกลับโดยst_dev
stat
ไม่มีวิธีพกพาในการทำเช่นนี้จากเชลล์สคริปต์ ระบบบางระบบมีstat
ยูทิลิตี้ แต่ไวยากรณ์ของมันแตกต่างกันไป:
stat
รายงานฟิลด์เมื่อเรียกเป็นst_dev
stat -c %D -- "$file"
stat
ที่เข้ากันได้กับ GNU coreutils คนอื่นstat
ไม่มี%c
ตัวเลือก; คุณสามารถใช้stat -t -- "$file" | awk '{print $8}'
แต่จะใช้งานได้เฉพาะถ้าชื่อไฟล์ไม่มีช่องว่างหรือstat -t -- "$file" | awk 'END {print $(NF-8)}'
copes ที่มีชื่อไฟล์โดยพลการ แต่ไม่ได้มีการเพิ่มฟิลด์ในอนาคตเพื่อstat
เอาท์พุทstat
ยูทิลิตี้stat -f %d -- "$file"
ที่ต้องใช้stat
ยูทิลิตี้หาก Perl พร้อมใช้งานคุณสามารถใช้
perl -e 'print ((stat($ARGV[0]))[0])' -- "$file"
และทำการเปรียบเทียบ:
perl -e 'exit((stat($ARGV[0]))[0] != (stat($ARGV[1]))[0])' -- "$file1" "$file2"
โปรดทราบว่ามีบางกรณีมุมที่ผลลัพธ์ที่ต้องการไม่ชัดเจน ตัวอย่างเช่นกับม้าผูกลินุกซ์หลังmount --bind /foo /bar
, /foo
และ/bar
จะถือว่าเป็นระบบแฟ้มเดียวกัน เป็นไปได้เสมอที่ไฟล์ทั้งสองนั้นจะอยู่ในอุปกรณ์เดียวกัน แต่คุณจะไม่มีทางรู้ตัวอย่างเช่นหากไฟล์นั้นอยู่บนเครือข่ายที่แตกต่างกันสองจุดไคลเอนต์จะไม่มีทางรู้ว่าเซิร์ฟเวอร์กำลังส่งออกระบบไฟล์ที่แตกต่างกันหรือไม่
หากไฟล์เป็นไดเรกทอรีและคุณสามารถเขียนถึงมันได้อีกวิธีหนึ่งคือการสร้างไฟล์ชั่วคราวและพยายามสร้างฮาร์ดลิงก์ อันนี้รายงานผลลัพธ์เชิงลบข้ามการเชื่อมโยงกับ Linux
tmp1=$(TMPDIR=$dir1 mktemp)
tmp2=$(TMPDIR=$dir2 mktemp)
if ln -f -- "$tmp1" "$tmp2"; then
echo "$dir1 and $dir2 are on the same filesystem, which supports hard links"
fi
rm -f "$tmp1" "$tmp2"
df
ไม่ได้ให้ชื่ออุปกรณ์เสมอไป แต่บางครั้งก็มีการเชื่อมโยงกับมันเหมือน/dev/disk/by-uuid/ca09b761-ae1b-450f-8a46-583327b48fb4
ทำให้df
ไม่น่าเชื่อถือ ตัวเลือกเดียวที่เชื่อถือได้จนถึงขณะนี้ใช้stat
โซลูชันแบบอิง
df
รายงานสำหรับอุปกรณ์มันสอดคล้องกันระหว่างการเรียกใช้สองรายการดังนั้นจึงเป็นการเปรียบเทียบ
df
รายงานเดียว/dev/sda6
และ/dev/disk/by-uuid/ca09b...
ทั้งที่อ้างถึงอุปกรณ์เดียวกัน แต่มีจุดเชื่อมต่อที่แตกต่างกัน การทดสอบการเปรียบเทียบสตริงล้มเหลวอย่างชัดเจนเมื่อพยายามกับไฟล์จากแต่ละจุดเชื่อมต่อ
mount /dev/sda6 /mnt1
ตามด้วยmount /dev/sda6 /mnt2
งานที่มีเสน่ห์ cat /proc/mounts
ไม่เป็นไร อย่างไรก็ตามเป็นเพียงตั้งแต่ Wheezy ที่/dev/disk/by-uuid/ca09b...
แสดงdf
เป็นอุปกรณ์สำหรับระบบไฟล์รูท ความพยายามเพิ่มเติมในการติดตั้งโดยใช้ simlink นี้หรือUUID=ca09b...
ไวยากรณ์การเชื่อมต่อไม่สิ้นสุดแสดงสิ่งอื่นนอกเหนือจาก/dev/sda6
ในdf
(ฉันไม่ทราบวิธีการทำซ้ำสิ่งที่ทำในระหว่างกระบวนการบู๊ต แต่นั่นไม่ใช่ข้อกังวลที่นี่)
test $(df -P $path1 $path2 | awk '{if (NR!=1) {print $6}}' | uniq | wc -l) -eq 1
ทำงานร่วมกับเส้นทางจำนวนเท่าใดก็ได้
$6
) ไม่ใช่ชื่ออุปกรณ์ ( $1
) เพื่อที่จะไม่เป็นปัญหา
การแก้ปัญหาจะเข้าใจผิดที่ดีที่สุดที่มีอยู่ใน POSIX คือการเปรียบเทียบของไฟล์ฯรหัสอุปกรณ์ให้โดยสถิติ (2) ฟังก์ชั่น
Perl มีคล้ายกันฟังก์ชั่นสถิติเป็นกิลส์ ชี้ให้เห็น :
perl -e 'exit((stat($ARGV[0]))[0] != (stat($ARGV[1]))[0])' -- file1 file2
แต่ "วิธี POSIX" คือการใช้โปรแกรม C เช่น:
./checksamedev file1 file2
รหัสแหล่งใดเป็นดังนี้:
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
int main(int argc, char* argv[]) {
struct stat s1, s2;
if( argc==3 && lstat(argv[1], &s1)==0 && lstat(argv[2], &s2)==0 )
return !(s1.st_dev == s2.st_dev);
return 2;
}
หากรหัสอุปกรณ์ของไฟล์ทั้งสองเท่ากันพวกเขาจะโฮสต์ในระบบไฟล์เดียวกันซึ่งในกรณีนี้คำสั่งดังกล่าวส่งกลับ 0 (ค่าอื่น ๆ ) echo $?
ตรวจสอบกับ
วิธีนี้ใช้งานได้ดีกับการเชื่อมต่อแบบผูก แต่อาจจะไม่ได้ผลเมื่อติดตั้งแบบเครือข่าย