Cách kiểm tra xem $ PWD có phải là thư mục con của một đường dẫn cụ thể không


25

Ví dụ: kiểm tra nếu $PWDlà thư mục con của / home. Nói cách khác, tôi đang tìm kiếm một hoạt động chuỗi bash để kiểm tra xem một chuỗi có bắt đầu bằng chuỗi khác không.

Câu trả lời:


26

Nếu bạn muốn kiểm tra một cách đáng tin cậy liệu một thư mục có phải là thư mục con của thư mục khác hay không, bạn sẽ cần nhiều hơn chỉ là kiểm tra tiền tố chuỗi. Câu trả lời của Gilles mô tả chi tiết cách thực hiện bài kiểm tra này đúng cách.

Nhưng nếu bạn muốn kiểm tra tiền tố chuỗi đơn giản (có thể bạn đã bình thường hóa đường dẫn của mình?), Đây là một cách tốt:

test "${PWD##/home/}" != "${PWD}"

Nếu $PWDbắt đầu bằng "/ home /", nó sẽ bị xóa ở bên trái, điều đó có nghĩa là nó sẽ không khớp với bên phải, vì vậy "! =" Trả về đúng.


1
+1 hoàn hảo và đối với trường hợp tổng quát hơn: [ "${PWD##$VAR}" != "$PWD" ]Và nếu đây là [code-golf] ( stackoverflow.com/questions/tagged/code-golf)question bạn đã đánh bại tôi bằng hai ký tự ;-) Ngoài ra, nó có vẻ dễ đọc hơn ...
Tobias Kienzler

FWIW, điều này cũng có thể hữu ích:${PWD/#$HOME/\~}
user1338062

Được rồi, nhưng về PWD = "/ home /../ etc /"
Alexis Peters

1
@AlexisPeter: Bạn nói đúng: Tôi đang tập trung vào phần "tiền tố chuỗi" của câu hỏi và tôi đã chỉnh sửa để làm cho nó rõ ràng hơn. Gilles đã bao quát độc đáo cách thích hợp để kiểm tra các thư mục con.
Jander 22/03/2016

1
Sử dụng "${PWD%%/subdir*}"để phát hiện xem người dùng hiện đang ở subdirhoặc trong thư mục con của subdir, vì %% bắt giữ từ cuối chuỗi thay vì bắt đầu. Điều này sẽ hữu ích cho bất kỳ ai đang tìm kiếm thêm thông tin về việc thay thế tham số: tldp.org/LDP/abs/html/parameter-substlation.html
George Pantazes

33

Để kiểm tra xem một chuỗi có phải là tiền tố của chuỗi khác hay không, trong bất kỳ shell kiểu Bourne nào:

case $PWD/ in
  /home/*) echo "home sweet home";;
  *) echo "away from home";;
esac

Nguyên tắc tương tự làm việc cho một bài kiểm tra hậu tố hoặc chuỗi con. Lưu ý rằng trong các casecấu trúc, không giống như trong tên tệp, *khớp với bất kỳ ký tự nào, kể cả ký tự /đầu tiên ..

Trong các shell thực hiện [[ … ]]cú pháp (ví dụ bash, ksh và zsh), nó có thể được sử dụng để khớp một chuỗi với một mẫu. (Lưu ý rằng [lệnh chỉ có thể kiểm tra các chuỗi cho đẳng thức.)

if [[ $PWD/ = /home/* ]]; then 

Nếu bạn đang kiểm tra cụ thể liệu thư mục hiện tại có ở bên dưới hay không /home, thì kiểm tra chuỗi con đơn giản là không đủ, vì các liên kết tượng trưng.

Nếu /homelà một hệ thống tệp của riêng nó, hãy kiểm tra xem thư mục hiện tại ( .) có nằm trong hệ thống tệp đó không.

if [ "$(df -P . | awk 'NR==2 {print $6}')" = "/home" ]; then
  echo 'The current directory is on the /home filesystem'
fi

Nếu bạn có NetBSD, OpenBSD hoặc GNU (tức là Linux) readlink, bạn có thể sử dụng readlink -fđể loại bỏ các liên kết tượng trưng từ một đường dẫn.

case $(readlink -f .)/ in $(readlink -f /home)/*) 

Nếu không, bạn có thể sử dụng pwdđể hiển thị thư mục hiện tại. Nhưng bạn phải cẩn thận không sử dụng shell được tích hợp nếu shell của bạn theo dõi cdcác lệnh và giữ tên bạn đã sử dụng để truy cập vào thư mục thay vì vị trí thực tế của nó.

case $(pwd -P 2>/dev/null || env PWD= pwd)/ in
  "$(cd /home && { pwd -P 2>/dev/null || env PWD= pwd; })"/*) 

+1 Cảm ơn câu trả lời thấu đáo này. Tôi đã không xem xét các liên kết và đặc thù của hệ thống tập tin khi hỏi điều này, nhưng chắc chắn là rất tốt để biết
Tobias Kienzler

8

Phiên bản thô:

[ ${PWD:0:6} = "/home/" ]

Có nhược điểm là người ta phải đếm các ký tự trước và người ta không thể thay thế /home/bằng một cái gì đó chung chung như thế nào $1.

chỉnh sửa (cảm ơn @Michael) để tổng quát hóa để so sánh với $VARngười ta có thể sử dụng

[ "${PWD:0:${#VAR}}" = $VAR ]

4
${#var}là độ dài của $var, vì vậy bạn có thể khái quát nó thành[ "${PWD:0:${#1}}" = "$1" ]
Michael Mrozek

@Michael Mrozek ♦: Cảm ơn, hoạt động hoàn hảo :)
Tobias Kienzler

2

Tôi không hiểu câu hỏi quá rõ, nhưng để tìm cha mẹ của $ PWD , hãy làm dirname $PWD. Để tìm cha mẹ của cha mẹ, hãy chạy dirname $(dirname $PWD), v.v.


Điều đó sẽ chỉ hoạt động nếu tôi biết chiều sâu, nếu không tôi sẽ kết thúc /. Ok, tôi có thể kiểm tra đệ quy, nhưng không có gì dễ dàng hơn?
Tobias Kienzler

1
@tob Nếu chỉ tôi biết lập trình shell ;-)
tshepang

1

Sử dụng awk:

echo $PWD | awk -v h="/home" '$0 ~ h {print "MATCH"}'

+1 để làm việc, nhưng chậm hơn một chút so với thử nghiệm bash bản địa
Tobias Kienzler

0

Hừm, thật đáng tiếc khi [không có tùy chọn STRING1 starts with STRING2điều kiện thử nghiệm .

Bạn có thể thử echo $PWD | grep '^$VAR', nhưng nó có thể thất bại theo những cách thú vị khi VARchứa các biểu tượng đặc biệt.

awk's indexchức năng nên có thể làm các trick. Nhưng tất cả điều này dường như quá nặng đối với một điều dễ dàng như vậy để kiểm tra.


[[không regrec vì vậy bạn sẽ bắt đầu với [[$ PWD = ~ ^ \ / home \ /]]
teknopaul

0

Nếu phần tìm kiếm của đường dẫn được tìm thấy, tôi "làm trống" biến:

[[ -z "${PWD//*\/home\/*/}" ]] && echo "toto"
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.