Cara memeriksa apakah $ PWD adalah subdirektori dari path yang diberikan

25

Misalnya, periksa apakah $PWDsubdirektori dari / home. Dengan kata lain saya sedang mencari operasi string bash untuk memeriksa apakah satu string dimulai dengan yang lain.

Tobias Kienzler
sumber

Jawaban:

26

Jika Anda ingin menguji apakah suatu direktori adalah subdirektori dari direktori lain, Anda akan membutuhkan lebih dari sekadar pemeriksaan awalan string. Jawaban Gilles menjelaskan secara rinci bagaimana melakukan tes ini dengan benar.

Tetapi jika Anda menginginkan pemeriksaan awalan string sederhana (mungkin Anda sudah menormalkan jalur Anda?), Ini bagus:

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

Jika $PWDdimulai dengan "/ home /", itu akan dilepas di sisi kiri, yang berarti tidak akan cocok dengan sisi kanan, jadi "! =" Mengembalikan true.

Jander
sumber
1
+1 sempurna, dan untuk kasus yang lebih umum: [ "${PWD##$VAR}" != "$PWD" ]Dan jika ini adalah [kode-golf] ( stackoverflow.com/questions/tagged/code-golf)question Anda akan mengalahkan saya dengan dua karakter ;-) Juga terlihat lebih mudah dibaca ...
Tobias Kienzler
FWIW, ini mungkin juga berguna:${PWD/#$HOME/\~}
user1338062
Baiklah, tapi bagaimana dengan PWD = "/ home /../ etc /"
Alexis Peters
1
@AlexisPeters: Anda benar: Saya berfokus pada bagian "awalan string" dari pertanyaan, dan saya telah mengeditnya untuk membuatnya lebih jelas. Gilles telah membahas dengan baik cara yang tepat untuk memeriksa subdirektori.
Jander
1
Gunakan "${PWD%%/subdir*}"untuk mendeteksi apakah pengguna saat ini berada di subdiratau dalam subdirektori subdir, karena %% menangkap dari akhir string, bukan dari awal. Ini harus bermanfaat bagi siapa pun yang mencari informasi lebih lanjut tentang substitusi parameter: tldp.org/LDP/abs/html/parameter-substitution.html
George Pantazes
33

Untuk menguji apakah suatu string adalah awalan dari yang lain, dalam shell gaya Bourne apa pun:

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

Prinsip yang sama berfungsi untuk tes sufiks atau substring. Perhatikan bahwa dalam casekonstruksi, tidak seperti dalam nama file, *cocok dengan karakter apa pun, termasuk a /atau inisial ..

Dalam shell yang mengimplementasikan [[ … ]]sintaksis (yaitu bash, ksh dan zsh), itu dapat digunakan untuk mencocokkan string dengan suatu pola. (Perhatikan bahwa [perintah hanya dapat menguji string untuk kesetaraan.)

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

Jika Anda secara khusus menguji apakah direktori saat ini berada di bawahnya /home, tes substring sederhana tidak cukup, karena tautan simbolik.

Jika /homeadalah filesystem-nya sendiri, uji apakah direktori saat ini ( .) ada pada filesystem itu.

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

Jika Anda memiliki NetBSD, OpenBSD atau GNU (yaitu Linux) readlink, Anda dapat menggunakan readlink -funtuk menghapus tautan simbolik dari sebuah jalur.

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

Jika tidak, Anda dapat menggunakan pwduntuk menampilkan direktori saat ini. Tetapi Anda harus berhati-hati untuk tidak menggunakan shell built-in jika shell Anda melacak cdperintah dan menjaga nama yang Anda gunakan untuk mencapai direktori daripada lokasi "aktual".

case $(pwd -P 2>/dev/null || env PWD= pwd)/ in
  "$(cd /home && { pwd -P 2>/dev/null || env PWD= pwd; })"/*) 
Gilles 'SANGAT berhenti menjadi jahat'
sumber
+1 Terima kasih atas jawaban lengkap ini. Saya tidak mempertimbangkan tautan dan keanehan sistem file ketika menanyakan hal ini, tetapi itu pasti baik untuk diketahui
Tobias Kienzler
8

Versi kasar:

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

Memiliki kelemahan yaitu seseorang harus menghitung karakter terlebih dahulu dan seseorang tidak dapat mengganti /home/dengan sesuatu yang umum seperti $1.

sunting (terima kasih @Michael) untuk generalisasi untuk dibandingkan dengan yang $VARdapat digunakan

[ "${PWD:0:${#VAR}}" = $VAR ]
Tobias Kienzler
sumber
4
${#var}adalah panjangnya $var, sehingga Anda dapat menggeneralisasikannya sebagai[ "${PWD:0:${#1}}" = "$1" ]
Michael Mrozek
@Michael Mrozek ♦: Terima kasih, bekerja dengan sangat baik :)
Tobias Kienzler
2

Saya tidak mengerti pertanyaannya dengan baik, tetapi untuk menemukan orang tua dari $ PWD , lakukan dirname $PWD. Untuk menemukan induk dari induk, jalankan dirname $(dirname $PWD), dan seterusnya ...

tepang
sumber
Itu hanya akan berhasil jika saya tahu kedalamannya, kalau tidak saya akan berakhir dengan /. Oke, saya bisa mengeceknya secara rekursif, tetapi tidak adakah yang lebih mudah?
Tobias Kienzler
1
@tob Kalau saja aku tahu pemrograman shell ;-)
tshepang
1

Menggunakan awk:

echo $PWD | awk -v h="/home" '$0 ~ h {print "MATCH"}'
dogbane
sumber
+1 untuk bekerja, tetapi sedikit lebih lambat daripada tes bash asli
Tobias Kienzler
0

Hm, sayang sekali yang [tidak memiliki opsi STRING1 starts with STRING2kondisi pengujian .

Anda dapat mencoba echo $PWD | grep '^$VAR', tetapi bisa gagal dengan cara yang menarik ketika VARberisi simbol-simbol khusus.

awk's indexfungsi harus dapat melakukan trik. Tetapi semua ini tampaknya terlalu berat untuk hal yang mudah untuk diuji.

alex
sumber
[[apakah regexp jadi Anda bisa mulai dengan [[$ PWD = ~ ^ \ / home \ /]]
teknopaul
0

Jika bagian yang dicari dari jalur ditemukan, saya "mengosongkan" variabel:

[[ -z "${PWD//*\/home\/*/}" ]] && echo "toto"

sumber