Bash conditionals: how to “and” expressions? (jika [! -z $ VAR && -e $ VAR])

281

Saya kira saya tidak jelas tentang bagaimana melakukan tes "dan". Saya ingin memastikan ada argumen yang bekerja dengan baik [ -e $VAR ], tetapi ternyata itu juga mengevaluasi benar pada string kosong; yang tidak saya inginkan.

Bagaimana saya dan mereka bersama? Atau ada tes unary lain yang memenuhi apa yang saya inginkan?

atxdba
sumber

Jawaban:

532
if [ ! -z "$var" ] && [ -e "$var" ]; then
      # something ...
fi
jaypal singh
sumber
9
Solusi ini berfungsi bahkan dalam cangkang yang sepenuhnya sesuai dengan POSIX dan karenanya juga dalam bash; namun, untuk memanfaatkan sepenuhnya "bashism", lihat jawaban @ paxdiablo.
mklement0
2
Sangat senang melihat ini disarankan daripada yang usang -a.
Charles Duffy
1
Saya menemukan satu lagi penjelasan yang sangat bagus dan terperinci - stackoverflow.com/questions/3601515/…
valentt
70

Dari halaman bashmanual:

[[ expression ]] - mengembalikan status 0 atau 1 tergantung pada evaluasi ekspresi ekspresi bersyarat.

Dan, untuk ekspresi, salah satu opsi adalah:

expression1 && expression2- benar jika keduanya expression1dan expression2benar.

Jadi Anda bisa andbersama mereka sebagai berikut ( -nadalah kebalikan dari -zsehingga kita dapat menyingkirkan !):

if [[ -n "$var" && -e "$var" ]] ; then
    echo "'$var' is non-empty and the file exists"
fi

Namun, saya pikir itu tidak diperlukan dalam kasus ini, -e xyzzybenar jika xyzzy file tersebut ada dan dapat dengan mudah menangani string kosong. Jika itu yang Anda inginkan maka Anda sebenarnya tidak memerlukan -zcek kosong:

pax> VAR=xyzzy
pax> if [[ -e $VAR ]] ; then echo yes ; fi
pax> VAR=/tmp
pax> if [[ -e $VAR ]] ; then echo yes ; fi
yes

Dengan kata lain, cukup gunakan:

if [[ -e "$var" ]] ; then
    echo "'$var' exists"
fi
paxdiablo
sumber
1
Kita dapat mempersingkatnya dengan[[ -e "$var" ]] && echo "'$var' exists"
jaypal singh
1
Ya, jika itu adalah satu-liner (seperti contoh saya). Saya tidak akan melakukan itu jika blok kondisional jauh lebih kompleks.
paxdiablo
dalam hal hanya ada satu - mungkin bahkan satu - perintah, masuk akal untuk menggunakan formulir ini karena lebih pendek
avp
9
if [ -n "$var" -a -e "$var" ]; then
    do something ...
fi

 

Slava Semushin
sumber
10
Karena POSIXtidak mendefinisikan perilaku [dengan set tes yang kompleks, kita harus menghindari menggunakan -aatau -odengan [. Saya membacanya di sini .
jaypal singh
2
@ jaypal-singh Anda benar, tetapi topik memiliki bashtag dan tidak menyebutkan tentang POSIX, jadi saya memposting versi ini yang berfungsi di bawah bashdan beberapa shell modern lainnya.
Slava Semushin
2
Jika Anda mengasumsikan penggunaan bashatau kerang modern lainnya, bahkan ada lebih sedikit alasan untuk merekomendasikan -a.
chepner
Bahkan dengan bash, cara tes ini berperilaku tidak didefinisikan dengan baik dalam semua kasus sudut. Pertimbangkan [ "$var1" -o "$var2" ]; jika var1=(dan var2=), maka yang kita miliki adalah ujian apakah -otidak kosong, bukan apakah salah satu var1atau var2tidak kosong. Ambiguitas semacam ini adalah satu-satunya alasan yang sah untuk x$varungkapan dalam testperintah modern (yaitu, pasca-90-an) dengan kutipan yang benar, dan idiom itu harus mati dalam api.
Charles Duffy
4

Cukup kutip variabel Anda:

[ -e "$VAR" ]

Ini mengevaluasi [ -e "" ]apakah $VARkosong.

Versi Anda tidak berfungsi karena dievaluasi ke [ -e ]. Sekarang dalam kasus ini, bash hanya memeriksa apakah argumen tunggal ( -e) adalah string yang tidak kosong.

Dari halaman manual:

menguji dan [mengevaluasi ekspresi kondisional menggunakan seperangkat aturan berdasarkan jumlah argumen. ...

1 argumen

Ungkapannya benar jika dan hanya jika argumennya tidak nol.

(Juga, solusi ini memiliki manfaat tambahan untuk bekerja dengan nama file yang mengandung spasi)

pengguna123444555621
sumber
1

Saya menemukan jawaban sekarang. Terima kasih atas saran Anda!

for e in ./*.cutoff.txt; do
if grep -q -E 'COX1|Cu-oxidase' $e
then
    echo xyz >$e.match.txt
else
    echo
fi

if grep -q -E 'AMO' $e
then
    echo abc >$e.match.txt
else
    echo
fi; done

Ada komentar tentang itu? Tampaknya tidak efisien untuk melakukan grep dua kali, tetapi berhasil ...

rororo
sumber