Kiểm tra nếu 2 thư mục được lưu trữ trên cùng một phân vùng trên Linux


9

Làm thế nào tôi có thể kiểm tra nếu /my/dirtrên cùng một phân vùng như /?

Điều này là để tích hợp trong một kịch bản. Gắn kết nên được xử lý chính xác. Giải pháp tương thích POSIX được chào đón.


Gắn kết Bind của Bind nên được xử lý chính xác. Nhưng những gì bạn cho là chính xác? Câu hỏi của bạn có thể được giải thích một trong hai cách.
Gilles 'SO- ngừng trở nên xấu xa'

@Gilles Trong tiêu đề ban đầu tôi đã viết "được lưu trữ" thay vì "được gắn kết", ai đó đã chỉnh sửa thêm sự nhầm lẫn IMHO. Tuy nhiên, câu hỏi của tôi rất rõ ràng: "trên cùng một phân vùng", đó là trên cùng một phân vùng vật lý, bất kể đường dẫn hoặc điểm gắn kết được sử dụng để truy cập vào hai tệp / thư mục.
Totor

Câu trả lời:


6

Bạn có thể kiểm tra điều này với stat:

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

Hiển thị cho bạn số thiết bị và nơi thư mục của bạn được gắn kết.


1
Đẹp, nhưng statlệnh shell không phải là POSIX ...
Totor

Không? Làm sao bạn biết?

Không có trong danh sách này .
Totor

Ôi lỗi của tôi. Nhưng lần sau hiển thị liên kết này trước.

5

Lệnh sau đây cung cấp một tên duy nhất cho điểm gắn kết chứa tệp $file:

df -P -- "$file" | awk 'NR==2 {print $1}'

Điều này hoạt động trên bất kỳ hệ thống POSIX . Các -Ptùy chọn áp đặt một định dạng có thể dự đoán; trường đầu tiên của dòng thứ hai là tên hệ thống tập tin tên lửa. Do đó, để kiểm tra hai tệp nằm dưới cùng một điểm gắn kết:

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

Hoặc, để lưu một vài lời mời quy trình:

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

Một vài hệ điều hành có thể có khoảng trắng trong tên âm lượng. Không có cách hoàn toàn đáng tin cậy để phân tích dfđầu ra trong trường hợp này.

Trong phần mềm này, bạn có thể xác định hệ thống tệp chứa tệp theo st_devtrường được trả về stat. Không có cách di động để làm điều này từ một kịch bản shell. Một số hệ thống có một stattiện ích, nhưng cú pháp của nó khác nhau:

  • Trên Linux không nhúng, Cygwin hoặc các hệ thống khác có lõi GNU, statbáo cáo st_devtrường khi được gọi là stat -c %D -- "$file".
  • Một số cài đặt BusyBox bao gồm một cài đặt stattương thích với lõi GNU. Những người khác có statmà không có %ctùy chọn; bạn có thể sử dụng stat -t -- "$file" | awk '{print $8}'nhưng điều này chỉ hoạt động nếu tên tệp không chứa khoảng trắng hoặc stat -t -- "$file" | awk 'END {print $(NF-8)}'đối phó với tên tệp tùy ý nhưng không có các trường bổ sung trong tương lai vào statđầu ra.
  • Các hệ thống BSD có một stattiện ích khác nhau đòi hỏi stat -f %d -- "$file".
  • Solaris, AIX và những người khác không có stattiện ích.

Nếu Perl có sẵn, bạn có thể sử dụng

perl -e 'print ((stat($ARGV[0]))[0])' -- "$file"

và để làm so sánh:

perl -e 'exit((stat($ARGV[0]))[0] != (stat($ARGV[1]))[0])' -- "$file1" "$file2"

Lưu ý rằng có một số trường hợp góc mà kết quả mong muốn không rõ ràng. Ví dụ, với gắn kết ràng buộc Linux, sau mount --bind /foo /bar, /foo/barđược coi là hệ thống tập tin tương tự. Luôn có khả năng hai tệp thực sự nằm trên cùng một thiết bị nhưng bạn sẽ không bao giờ biết: ví dụ: nếu các tệp nằm trên hai giá treo mạng khác nhau, máy khách không có cách nào để biết liệu máy chủ có xuất các hệ thống tệp khác nhau hay không.

Nếu các tệp là thư mục và bạn có thể ghi vào chúng, một phương pháp khác là tạo một tệp tạm thời và cố gắng tạo một liên kết cứng. Điều này báo cáo một kết quả tiêu cực trên các liên kết gắn kết 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"

Vấn đề: dfkhông phải lúc nào cũng cung cấp tên thiết bị, nhưng đôi khi một liên kết tượng trưng đến nó như /dev/disk/by-uuid/ca09b761-ae1b-450f-8a46-583327b48fb4làm cho dfkhông đáng tin cậy. Tùy chọn đáng tin cậy duy nhất cho đến nay là sử dụng statgiải pháp dựa trên cơ sở.
Totor

@Totor Điều đó không thành vấn đề: bất kỳ tên nào dfbáo cáo cho thiết bị, nó phù hợp giữa hai cách gọi, vì vậy việc so sánh là được.
Gilles 'SO- ngừng trở nên xấu xa'

Không, nó không hoạt động, tôi đã thử nó. Trên Debian Wheezy ở đây, một dfbáo cáo duy nhất /dev/sda6/dev/disk/by-uuid/ca09b..., cả hai đều đề cập đến cùng một thiết bị, nhưng các điểm gắn kết khác nhau. Kiểm tra so sánh chuỗi rõ ràng thất bại khi thử với các tệp từ mỗi điểm gắn kết.
Totor

@Totor Thông thường bạn không thể có cùng một thiết bị khối được gắn hai lần. Như tôi chỉ ra trong câu trả lời của mình, có những trường hợp góc như gắn kết liên kết có thể hoặc không thể được báo cáo là khác biệt.
Gilles 'SO- ngừng trở nên xấu xa'

Tuy nhiên, nó hoạt động hoàn hảo trên Debian Squeeze và Wheezy: mount /dev/sda6 /mnt1tiếp theo là các mount /dev/sda6 /mnt2tác phẩm như một bùa mê. cat /proc/mountslà tốt với nó Tuy nhiên, chỉ vì Wheezy /dev/disk/by-uuid/ca09b...được hiển thị dfdưới dạng thiết bị cho hệ thống tập tin gốc. Nỗ lực hơn nữa để gắn kết nó bằng cách sử simlink này hoặc UUID=ca09b...gắn cú pháp không kết thúc cho thấy bất cứ điều gì khác hơn /dev/sda6trong df(Tôi không biết làm thế nào để tái tạo những gì nó thực hiện trong suốt quá trình khởi động, nhưng đó không phải là mối quan tâm ở đây).
Totor

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

Hoạt động với bất kỳ số lượng đường dẫn.


Phân tích đầu ra của dfkhông luôn luôn là một ý tưởng tốt .
Joseph R.

1
@Totor Tôi đang kiểm tra mountpoint ( $6), không phải tên thiết bị ( $1), vì vậy đó không phải là vấn đề.
n.st

1
@JosephR Đó là thứ tốt nhất có trong POSIX. n.st: tại sao không kiểm tra trường đầu tiên? Không quan trọng đường dẫn nào được sử dụng để truy cập thiết bị, nếu đó là cùng một điểm gắn kết thì đầu ra sẽ nhất quán.
Gilles 'SO- ngừng trở thành ác quỷ'

Điều này không hoạt động với gắn kết liên kết.
Totor

0

Giải pháp hoàn hảo nhất có sẵn trong POSIX là so sánh ID thiết bị của các tệp được cung cấp bởi chức năng stat (2) .

Perl có chức năng thống kê tương tự như Gilles đã chỉ ra :

perl -e 'exit((stat($ARGV[0]))[0] != (stat($ARGV[1]))[0])' -- file1 file2

nhưng "cách POSIX" là sử dụng chương trình C như:

./checksamedev file1 file2

mã nguồn nào như sau:

#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;
}

Nếu ID thiết bị của cả hai tệp bằng nhau, chúng được lưu trữ trên cùng một hệ thống tệp, trong trường hợp đó, các lệnh trên trả về 0 (giá trị khác). Kiểm tra với echo $?.

Điều này hoạt động tốt với các liên kết gắn kết, nhưng có lẽ sẽ không với các kết nối mạng.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.