Kiểm tra xem hai đường dẫn có giống nhau không, ngay cả khi chuỗi của chúng không khớp chính xác


0

Tôi có một tập lệnh phụ thuộc vào một số biến môi trường, một số trong đó là các đường dẫn

Kịch bản kiểm tra nếu nó đang được chạy trong thư mục chính xác bằng cách kiểm tra $(pwd)/expected-subdirlại$VARIABLE_PATH/expected_subdir

Tất nhiên nếu $VARIABLE_PATH == $(pwd)/(tôi tự nhiên thêm một dấu gạch chéo vào cuối biến khi gõ nó), thì chuỗi khớp không thành công mặc dù các thư mục có kỹ thuật lành mạnh.

Có cách nào để xác định duy nhất một thư mục, đưa ra một đường dẫn đến nó và xem liệu một đường dẫn khác sẽ định tuyến bạn đến cùng một vị trí không? Có thể đường dẫn đưa ra không lành mạnh, vì vậy kiểm tra này vẫn nên được thực hiện, nhưng dường như không cần thiết buộc đường dẫn phải khớp chính xác, khi một dấu gạch chéo hoặc thậm chí là một thư mục tương đối (đôi khi tôi biết những điều này có thể xấu) đến cùng một chỗ

Câu trả lời:


1

Câu trả lời khác này đề cập stat. Hãy cải thiện cách tiếp cận:

a="$(stat --format=%d:%i -- "$(pwd)/expected-subdir/")"         || printf "Error A\n" >&2
b="$(stat --format=%d:%i -- "$VARIABLE_PATH/expected-subdir/")" || printf "Error B\n" >&2
[ "$a" = "$b" ] || printf "Not the same path.\n" >&2

Ghi chú:

  • Chúng tôi đang sử dụng stat --format=, vì vậy không cần phân tích cú pháp nữa.
  • %dlà số thiết bị, %ilà số inode. Chỉ riêng cái sau là không đủ vì hai đối tượng trên các thiết bị khác nhau (hệ thống tệp) có thể có cùng số inode.
  • Vỏ đủ thông minh để xử lý riêng báo giá bên trong và bên ngoài $( ).
  • printf-s chỉ là sơ khai để xử lý lỗi. Trong kịch bản thực, bạn có thể muốn một cái gì đó như

    [ "$a" = "$b" ] || { printf "Not the same path.\n" >&2; exit 2; }
  • Đường dẫn không tồn tại sẽ làm cho statlỗi ném.

  • Chém chém rất quan trọng. Nếu foolà một symlink đến một thư mục, stat foosẽ kiểm tra symlink trong khi stat foo/sẽ kiểm tra thư mục. Hoặc nghiên cứu stat -Lvà sử dụng nó có thể.
  • --trong trường hợp $(pwd)hoặc $VARIABLE_PATHbắt đầu bằng -(xem hướng dẫn 10 ở đây ).

readlink -f(cũng được đề cập trong câu trả lời khác) và realpathtiện ích. Một trong số đó có thể là một cách tiếp cận tốt hơn stat. Nó phụ thuộc vào khía cạnh nào của các con đường là quan trọng đối với bạn. Sự khác biệt chính:

  1. Nếu /foo/bar/là một liên kết gắn kết /moo/baz/sau đó stat --format=%d:%isẽ cho bạn biết chúng giống nhau, nhưng readlinkhoặc realpathsẽ xem xét chúng khác nhau.
  2. Tình hình trở nên phức tạp với các liên kết tượng trưng và ... Xem man 1 realpath, đặc biệt -L-Pcác tùy chọn.

Với các liên kết tượng trưng có liên quan, nếu tập lệnh của bạn thay đổi thư mục lên ( /ví dụ: hướng tới cd ..), bạn có thể nhận được các kết quả khác nhau tùy thuộc vào nơi bạn bắt đầu, ngay cả khi stathoặc readlink -fnói hai điểm bắt đầu giống nhau (so sánh Tại sao lại ls ..hiển thị nội dung cha mẹ thực sự khi tôi ' m bên trong một thư mục liên kết tượng trưng? ). Hãy xem xét phương pháp này:

# early in the script
set -P
cd .   # seems like no-op but updates the PWD variable to physical path

Với các liên kết gắn kết có liên quan, nếu tập lệnh của bạn thay đổi thư mục, bạn có thể nhận được các kết quả khác nhau tùy thuộc vào nơi bạn bắt đầu, ngay cả khi statnói hai điểm bắt đầu giống nhau. Xem xét ví dụ với /foo/bar//moo/baz/(đã được giới thiệu ở trên). Rõ ràng nó /foo/có thể hoàn toàn khác /moo/. Nhưng cũng /foo/bar/abccó thể khác hơn /moo/baz/abcbởi vì bất kỳ abccó thể là một gắn kết độc lập với một cái gì đó khác. Vì vậy, không chỉ cd ..có thể đặt bạn ở một vị trí khác, mà còn cd abc.

Vâng, abccó thể là một tập tin. Điều gì nếu bạn liên kết một tập tin khác /moo/baz/abcnhưng không /foo/bar/abc? Các tập tin cảm nhận sẽ khác nhau ngay cả khi statnói rằng bạn đang ở cùng một nơi!

Bởi vì những vấn đề này bạn thực sự có thể thích readlinkhoặc realpathhơn stat.


stat, readlinkrealpathkhông được yêu cầu của POSIX. Trong trường hợp của bạn, một giải pháp di động có thể trông như thế này:

a="$(cd -P -- "expected-subdir" && pwd -P)"                || exit 1
b="$(cd -P -- "$VARIABLE_PATH/expected-subdir" && pwd -P)" || exit 1
[ "$a" = "$b" ] || { printf "Not the same path.\n" >&2; exit 2; }

Nó hoạt động bằng cách - theo cdmột trong hai đường dẫn và truy xuất nó với pwd. Các hoạt động này rõ ràng bị buộc phải hành động "vật lý" ( -P).

set -Pcũng không phải là POSIX. Nếu bạn muốn shell POSIX "giả lập" set -P, hãy thay thế cdpwd:

cd()  { command cd  -P "$@"; }
pwd() { command pwd -P "$@"; }

POSIX yêu cầu tùy chọn cuối cùng -Phoặc -Lcó hiệu lực, do đó pwd -Lvẫn truy xuất đường dẫn logic mặc dù chức năng "tiêm" -P; giống nhau cho cd -L.


1

Bạn có thể so sánh số inode của chúng, có thể được lấy từ ls -i

ls -di path/to/dir

( -dngăn không lscho hiển thị id inode cho nội dung của thư mục);

hoặc từ stat

stat path/to/dir | grep -o 'Inode:\ [0-9]*' | cut -d' ' -f2

Bạn cũng có thể sử dụng readlink -fđể có được đường dẫn đầy đủ đến thư mục.


Đối với kịch bản, có thể dễ sử dụng hơn find path/to/dir/ -maxdepth 0 -printf %i\\nvì nó chỉ inode chứ không phải tên. Việc maxdepth 0ngăn chặn một tìm kiếm sâu. Để an toàn hơn, hãy thêm %Dvì các nút chỉ là duy nhất cho mỗi đĩa, không phải trên toàn hệ thống.
MSalters
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.