ตรวจสอบว่า 2 ไดเรกทอรีโฮสต์บนพาร์ติชันเดียวกันบน Linux หรือไม่


9

ฉันจะตรวจสอบว่า/my/dirอยู่บนพาร์ติชันเดียวกันได้/หรือไม่?

นี่สำหรับการรวมภายในสคริปต์ การเชื่อมต่อแบบผูกควรได้รับการจัดการอย่างถูกต้อง ยินดีต้อนรับโซลูชันที่รองรับ POSIX


“ การติดตั้งผูกควรได้รับการจัดการอย่างถูกต้อง” แต่คุณคิดว่าอะไรถูกต้อง? คำถามของคุณสามารถตีความได้ทั้งสองทาง
Gilles 'หยุดชั่วร้าย'

@Gilles ในชื่อดั้งเดิมฉันเขียนว่า "โฮสต์" แทนที่จะเป็น "ติดตั้ง" มีคนแก้ไขการเพิ่มความสับสน IMHO แต่เนื้อหาคำถามของฉันชัดเจน: "บนพาร์ติชันเดียวกัน" ซึ่งอยู่ในฟิสิคัลพาร์ติชันเดียวกันไม่ว่าจะใช้พา ธ หรือจุดเชื่อมต่อใดในการเข้าถึงทั้งสองไฟล์ / ไดเรกทอรี
Totor

คำตอบ:


6

คุณสามารถตรวจสอบสิ่งนี้ด้วยสถิติ:

$ stat -c '%d %m' /proc/sys/
3 /proc

แสดงหมายเลขอุปกรณ์และตำแหน่งที่ติดตั้งไดเรกทอรีของคุณ


1
ที่ดี แต่statคำสั่งของเชลล์ไม่ POSIX ...
Totor

ไม่มี? คุณรู้ได้อย่างไร?

ไม่ได้อยู่ในรายการนี้
Totor

โอ้ฉันไม่ดี แต่ครั้งต่อไปแสดงลิงค์นี้ล่วงหน้า

5

คำสั่งต่อไปนี้ให้ชื่อเฉพาะสำหรับจุดเมานท์ที่มีไฟล์$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ยูทิลิตี้ แต่ไวยากรณ์ของมันแตกต่างกันไป:

  • ที่ไม่ฝัง Linux, Cygwin หรือระบบอื่น ๆ ที่มี coreutils GNU, statรายงานฟิลด์เมื่อเรียกเป็นst_devstat -c %D -- "$file"
  • การติดตั้ง BusyBox บางอย่างรวมถึงสิ่งstatที่เข้ากันได้กับ GNU coreutils คนอื่นstatไม่มี%cตัวเลือก; คุณสามารถใช้stat -t -- "$file" | awk '{print $8}'แต่จะใช้งานได้เฉพาะถ้าชื่อไฟล์ไม่มีช่องว่างหรือstat -t -- "$file" | awk 'END {print $(NF-8)}'copes ที่มีชื่อไฟล์โดยพลการ แต่ไม่ได้มีการเพิ่มฟิลด์ในอนาคตเพื่อstatเอาท์พุท
  • ระบบ BSD มีที่แตกต่างกันstatยูทิลิตี้stat -f %d -- "$file"ที่ต้องใช้
  • Solaris, AIX และอื่น ๆ ไม่มี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โซลูชันแบบอิง
Totor

@Totor ที่ไม่สำคัญ: ชื่ออะไรก็ตามที่dfรายงานสำหรับอุปกรณ์มันสอดคล้องกันระหว่างการเรียกใช้สองรายการดังนั้นจึงเป็นการเปรียบเทียบ
Gilles 'หยุดชั่วร้าย'

ไม่มันไม่ทำงานฉันทดสอบมัน บน Debian Wheezy ที่นี่จะมีdfรายงานเดียว/dev/sda6และ/dev/disk/by-uuid/ca09b...ทั้งที่อ้างถึงอุปกรณ์เดียวกัน แต่มีจุดเชื่อมต่อที่แตกต่างกัน การทดสอบการเปรียบเทียบสตริงล้มเหลวอย่างชัดเจนเมื่อพยายามกับไฟล์จากแต่ละจุดเชื่อมต่อ
Totor

@Totor ปกติแล้วคุณจะไม่สามารถติดตั้งอุปกรณ์บล็อกเดียวกันได้สองครั้ง ตามที่ฉันระบุในคำตอบของฉันมีกรณีมุมเช่นผูกติดซึ่งอาจหรืออาจไม่ได้รับรายงานว่าแตกต่างกัน
Gilles 'หยุดความชั่วร้าย'

แต่มันทำงานได้อย่างสมบูรณ์ใน Debian Squeeze และ Wheezy: mount /dev/sda6 /mnt1ตามด้วยmount /dev/sda6 /mnt2งานที่มีเสน่ห์ cat /proc/mountsไม่เป็นไร อย่างไรก็ตามเป็นเพียงตั้งแต่ Wheezy ที่/dev/disk/by-uuid/ca09b...แสดงdfเป็นอุปกรณ์สำหรับระบบไฟล์รูท ความพยายามเพิ่มเติมในการติดตั้งโดยใช้ simlink นี้หรือUUID=ca09b...ไวยากรณ์การเชื่อมต่อไม่สิ้นสุดแสดงสิ่งอื่นนอกเหนือจาก/dev/sda6ในdf(ฉันไม่ทราบวิธีการทำซ้ำสิ่งที่ทำในระหว่างกระบวนการบู๊ต แต่นั่นไม่ใช่ข้อกังวลที่นี่)
Totor

4
test $(df -P $path1 $path2 | awk '{if (NR!=1) {print $6}}' | uniq | wc -l) -eq 1

ทำงานร่วมกับเส้นทางจำนวนเท่าใดก็ได้


การแยกวิเคราะห์การส่งออกของdfเป็นไปไม่ได้เสมอความคิดที่ดี
Joseph R.

1
@Totor ฉันกำลังตรวจสอบจุดเมานท์ ( $6) ไม่ใช่ชื่ออุปกรณ์ ( $1) เพื่อที่จะไม่เป็นปัญหา
n.st

1
@JosephR มันดีที่สุดใน POSIX n.st: ทำไมไม่ตรวจสอบฟิลด์แรก ไม่สำคัญว่าจะใช้พา ธ ใดในการเข้าถึงอุปกรณ์หากเป็นจุดเชื่อมต่อเดียวกันผลลัพธ์จะสอดคล้องกัน
Gilles 'หยุดความชั่วร้าย'

สิ่งนี้ไม่สามารถใช้งานได้กับการผูกติด
Totor

0

การแก้ปัญหาจะเข้าใจผิดที่ดีที่สุดที่มีอยู่ใน 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 $?ตรวจสอบกับ

วิธีนี้ใช้งานได้ดีกับการเชื่อมต่อแบบผูก แต่อาจจะไม่ได้ผลเมื่อติดตั้งแบบเครือข่าย

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