Saya tahu saya bisa melakukannya
$ [ -w /home/durrantm ] && echo "writable"
writable
atau
$ test -w /home/durrantm && echo "writable"
writable
atau
$ [[ -w /home/durrantm ]] && echo "writable"
writable
Saya suka menggunakan sintaks ketiga. Apakah mereka setara dalam semua hal dan untuk semua kasus negatif dan tepi? Apakah ada perbedaan dalam portabilitas, mis. Antara bash di Ubuntu dan pada OS X atau versi bash yang lebih lama / lebih baru, mis. Sebelum / sesudah 4.0 dan apakah keduanya memperluas ekspresi dengan cara yang sama?
shell
posix
test
portability
Michael Durrant
sumber
sumber
[ … ]
vs[[ … ]]
vstest …
, ada jawaban yang lebih lengkap di sebagian besar pertanyaan duplikat ini .Jawaban:
[
adalah sinonim daritest
perintah dan secara bersamaan perintah bash builtin dan terpisah. Tapi[[
adalah kata kunci pesta dan bekerja di beberapa versi saja. Jadi untuk alasan portabilitas Anda lebih baik menggunakan satu[]
atautest
sumber
[
itu POSIX builtin atau Bash builtin?test
dan[
sama. Jika sebuah shell dapat melakukan evaluasi sendiri, itu menghemat proses Anda dan membuatnya agak lebih cepat, tetapi hasilnya harus sama.[
didefinisikan oleh POSIX dan karena itu portabel secara maksimal (yang tampaknya menjadi inti dari pertanyaan ini jika saya tidak salah)[
dantest
POSIX . Tampaknya tidak ada "yang direkomendasikan", meskipun satu-satunya perbedaan (?) Yang dapat saya temukan di antara mereka adalah bahwatest
"tidak akan mengenali argumen" - "[sebagai pembatas yang mengindikasikan akhir opsi]" (? - menyiratkan bahwa " -" yang diakui sebagai end-of-argumen untuk[
, yang saya tidak bisa benar-benar datang dengan kasus tes yang baik untuk tetap tapi saya ngelantur Gunakan yang Anda akan IMO,...[
terlihat elegan, tapitest
isclearly perintah)Ya, ada perbedaan. Yang paling portabel adalah
test
atau[ ]
. Ini adalah bagian dari spesifikasi POSIXtest
.The
if ... fi
konstruk juga ditentukan oleh POSIX dan harus benar-benar portabel.Ini
[[ ]]
adalahksh
fitur yang juga hadir dalam beberapa versibash
( semua yang modern ), dizsh
dan mungkin dalam yang lain tetapi tidak hadir dish
ataudash
atau berbagai cangkang sederhana lainnya.Jadi, untuk membuat skrip Anda portabel, gunakan
[ ]
,test
atauif ... fi
.sumber
bash
danzsh
telah mendukung[[
untuk waktu yang sangat lama (bash
menambahkannya di akhir 90-an,zsh
paling lambat tahun 2000, dan saya akan terkejut jika itu pernah kekurangan dukungan), jadi Anda tidak mungkin menemukan versi keduanya tanpa[[
. Mengalami shell yang sesuai dengan POSIX (sepertidash
) jauh lebih mungkin.[[
adalah bahwa ekspansi parameter tidak perlu dikutip:[[-f $file]]
event berfungsi jika$file
berisi karakter spasi.[[ $a =~ ^reg.*exp.*$' ]]
Harap dicatat, itu
[] && cmd
tidak sama denganif .. fi
konstruksi.Terkadang perilakunya sangat mirip dan Anda dapat menggunakannya
[] && cmd
sebagai gantinyaif .. fi
. Tapi hanya terkadang. Jika Anda memiliki lebih dari satu perintah untuk mengeksekusi jika kondisi atau Anda perluif .. else .. fi
hati-hati dan whatch logikanya.Beberapa contoh:
Tidak sama dengan
karena jika
ls
akan gagal,echo
akan dieksekusi yang tidak akan terjadi denganif
.Contoh lain:
tidak sama dengan
meskipun konstruksi ini akan bertindak sama
harap diperhatikan
;
setelah gema penting dan harus ada di sana.Jadi melanjutkan pernyataan di atas bisa kita katakan
[] && cmd
== jika perintah pertama berhasil maka jalankan perintah berikutnyaif .. fi
== jika kondisi (yang mungkin merupakan perintah tes juga) maka jalankan perintahJadi untuk portabilitas antara
[
dan hanya[[
digunakan[
.if
kompatibel dengan POSIX. Jadi, jika Anda harus memilih di antara[
danif
memilih melihat tugas Anda dan perilaku yang diharapkan.sumber
[ -z "$VAR" ] && { ls file; true; } || echo wiiii
. Ini sedikit lebih bertele-tele, tetapi masih lebih pendek dariif...fi
konstruksi.[
danif
sebagai pengganti, tetapi tidak. Ini sebenarnya&&
yang menggantikanif
.[
mengeksekusi beberapa kode dan mengembalikan status, sangat sukals
dangrep
mau.if
eksekusi cabang tergantung pada status pengembalian perintah (pernyataan) yang diberikan setelah if, bisa berupa perintah (pernyataan) apa pun.&&
mengeksekusi pernyataan berikutnya hanya jika yang sebelumnya mengembalikan 0, seperti sederhanaif..then..fi
.Sebenarnya
&&
yang menggantikanif
, bukantest
:if
pernyataan dalam tes skrip shell menguji apakah perintah mengembalikan status keluar "berhasil" (nol); dalam contoh Anda, perintahnya adalah[
.Jadi, sebenarnya ada dua hal yang berbeda di sini: perintah yang digunakan untuk menjalankan tes, dan sintaks yang digunakan untuk mengeksekusi kode berdasarkan hasil tes itu.
Perintah uji:
test
adalah perintah standar untuk mengevaluasi properti string dan file; dalam contoh Anda, Anda menjalankan perintahtest -w /home/durrantm
[
adalah alias dari perintah itu, sama-sama terstandarisasi, yang memiliki argumen terakhir wajib]
agar terlihat seperti ekspresi kurung; jangan tertipu, itu masih hanya sebuah perintah (Anda bahkan mungkin menemukan bahwa sistem Anda memiliki file bernama/bin/[
)[[
adalah versi tambahan dari perintah uji yang dibangun ke dalam beberapa shell, tetapi bukan bagian dari standar POSIX yang sama; itu termasuk opsi tambahan yang tidak Anda gunakan di siniEkspresi bersyarat:
&&
operator ( standar di sini ) melakukan operasi logika AND, dengan mengevaluasi dua perintah dan kembali 0 (yang mewakili true) jika mereka berdua return 0; itu hanya akan mengevaluasi perintah kedua jika yang pertama mengembalikan nol, sehingga dapat digunakan sebagai kondisi sederhanaif ... then ... fi
konstruk ( standar di sini ) menggunakan metode yang sama menilai "kebenaran", tetapi memungkinkan untuk daftar senyawa pernyataan dalamthen
klausa, daripada perintah tunggal diberikan oleh&&
hubungan arus pendek, dan menyediakanelif
danelse
klausa, yang sulit untuk menulis hanya menggunakan&&
dan||
. Perhatikan bahwa tidak ada tanda kurung di sekitar kondisi dalamif
pernyataan .Jadi, berikut ini semua sama-sama portabel, dan sepenuhnya setara, rendering dari contoh Anda:
test -w /home/durrantm && echo "writable"
[ -w /home/durrantm ] && echo "writable"
if test -w /home/durrantm; then echo "writable"; fi
if [ -w /home/durrantm ]; then echo "writable"; fi
Sementara yang berikut ini juga setara, tetapi kurang portabel karena sifat non-standar
[[
:[[ -w /home/durrantm ]] && echo "writable"
if [[ -w /home/durrantm ]]; then echo "writable"; fi
sumber
Untuk portabilitas, gunakan
test
/[
. Tetapi jika Anda tidak membutuhkan portabilitas, demi kewarasan diri Anda dan orang lain yang membaca skrip Anda gunakan[[
. :)Lihat juga
What is the difference between test, [ and [[ ?
di BashFAQ .sumber
Jika Anda ingin portabilitas di luar dunia seperti Bourne, maka:
adalah yang paling portabel. Ia bekerja di cangkang Bourne,
csh
danrc
keluarga.akan output
"writable"
bukanwritable
di kerang darirc
keluarga (rc
,es
,akanga
, di mana"
tidak istimewa).tidak akan bekerja di shell
csh
ataurc
keluarga pada sistem yang tidak memiliki[
perintah$PATH
(beberapa telah diketahui memilikitest
tetapi tidak[
alias).hanya bekerja di kulit keluarga Bourne.
hanya bekerja di
ksh
(tempat asalnya),zsh
danbash
(ketiganya dalam keluarga Bourne).Tidak ada yang akan bekerja di
fish
shell di mana Anda perlu:atau:
sumber
Alasan saya yang paling penting untuk memilih salah satu
if foo; then bar; fi
ataufoo && bar
apakah status keluar dari seluruh perintah itu penting.membandingkan:
dengan:
Anda mungkin berpikir mereka melakukan hal yang sama; namun jika
foo
gagal (atau salah, tergantung sudut pandang Anda) maka pada contoh pertama do_baz tidak akan dieksekusi, karena skrip akan keluar ... Scriptset -e
menginstruksikan shell untuk segera keluar jika ada perintah yang mengembalikan status palsu. Sangat berguna jika Anda melakukan hal-hal seperti:Anda tidak ingin skrip terus berjalan jika
cd
gagal karena alasan apa pun.sumber
foo
tidak akan membatalkan skrip dalam kedua kasus. Itu adalah kasus khusus untukset -e
(ketika perintah dievaluasi sebagai kondisi (di sebelah kiri beberapa && / || atau jika / saat / sampai / elsif ... kondisi). Kegagalanbar
akan keluar dari shell dalam kedua kasus.cd /some/directory && rm -rf -- *
ataucd /some/directory || exit; rm -rf -- *
(masih tidak menghapus file tersembunyi). Saya pribadi tidak suka ide menggunakanset -e
sebagai alasan untuk tidak berusaha menulis kode yang benar.