Pertimbangkan dua ekspresi kondisional expr1
dan expr2
, misalnya $i -eq $j
dan $k -eq $l
. Kita dapat menulis ini dalam bash
beberapa cara. Berikut ini dua kemungkinan
[[ expr1 || expr2 ]]
[[ expr1 ]] || [[ expr2 ]]
Saya cukup yakin saya telah melihat rekomendasi di sini bahwa yang kedua harus lebih disukai, tetapi saya tidak dapat menemukan bukti untuk mendukung ini.
Berikut ini contoh skrip yang tampaknya menunjukkan tidak ada perbedaan:
for i in 0 1
do
for j in 0 1
do
for k in 0 1
do
for l in 0 1
do
if [[ $i -eq $j || $k -eq $l ]]; then printf "1-yes\t"; else printf "1-no\t"; fi
if [[ $i -eq $j ]] || [[ $k -eq $l ]]; then printf "2-yes\n"; else printf "2-no\n"; fi
done
done
done
done
dan output menunjukkan bahwa kedua konstruk kondisi menghasilkan hasil yang sama:
1-yes 2-yes
1-yes 2-yes
1-yes 2-yes
1-yes 2-yes
1-yes 2-yes
1-no 2-no
1-no 2-no
1-yes 2-yes
1-yes 2-yes
1-no 2-no
1-no 2-no
1-yes 2-yes
1-yes 2-yes
1-yes 2-yes
1-yes 2-yes
1-yes 2-yes
Apakah ada manfaat menggunakan satu konstruksi di atas yang lain?
Untuk poin bonus, pertanyaan yang sama tetapi digeneralisasikan ke berbagai kondisi menggunakan ||
dan &&
. Sebagai contoh [[ expr1 && expr2 || expr3 ]]
,.
[
atautest
( tidak[[
), cariOB
tag (tertaut ke definisi "usang") dalam spesifikasi POSIX untuktest
. Dalamtest
, ada beberapa kasus patologis di mana tidak mungkin untuk mengetahui apakah(
atau)
dimaksudkan untuk menjadi sintaks yang berarti untuk perintah pengujian atau string yang akan diuji, sehingga orang yang mengabaikan penanda keusangan dan menggunakan sintaksis itu sebenarnya dapat membutuhkan sebaliknya."x$foo"
praktik usang ; dengan[[
, itu bukan masalah.Jawaban:
Saya pikir rekomendasi yang Anda lihat adalah untuk POSIX sh dan / atau
test
perintah yang berfungsi sebagai[
perintah, daripada[[
konstruk yang muncul di ksh (terima kasih Stéphane Chazelas untuk tipnya) dan juga digunakan misalnya dalam bash, zsh dan beberapa lainnya kerang.Dalam sebagian besar bahasa, seperti C, ketika klausa sudah diketahui benar atau salah, tidak perlu mengevaluasi bagian-bagian sisanya tergantung pada operasi: jika benar bukan setelah logis atau mengikutinya, jika salah bukan setelah logis dan , dll. Ini tentu saja memungkinkan misalnya untuk berhenti ketika pointer NULL dan tidak mencoba untuk men-dereference-kannya pada klausa berikutnya.
Tapi sh 's
[ expr1 -o expr2 ]
konstruk (termasuk implementasi bash) tidak melakukan hal ini: selalu mengevaluasi kedua belah pihak, ketika salah satu ingin hanya expr1 untuk dievaluasi. Ini mungkin dilakukan untuk kompatibilitas dengantest
implementasi perintah. Di sisi lain, sh||
dan&&
ikuti prinsip yang biasa: tidak dievaluasi jika tidak akan mengubah hasilnya.Jadi perbedaan yang perlu diperhatikan adalah:
yang menghasilkan:
Di atas, masing
[
- masing bisa diganti dengan/usr/bin/[
yang merupakan alias untuktest
perintah, digunakan sebelum[
dibuat built-in ke shell.Sementara dua konstruksi berikutnya:
atau
Hanya akan menghasilkan
true
dan membiarkaneffect
kosong:||
berperilaku dengan benar, dan[[
memperbaiki masalah ini juga.MEMPERBARUI:
Ketika @ StéphaneChazelas berkomentar, saya melewatkan beberapa perbedaan terkait dengan pertanyaan awal. Saya hanya akan menempatkan di sini yang paling penting (setidaknya bagi saya): prioritas operator.
Sementara shell tidak akan mempertimbangkan prioritas:
hasil (karena tidak ada prioritas dan dengan demikian pertama
true || true
dievaluasi, dan kemudian&& false
):di
[[ ]]
dalam&&
operator lebih diutamakan daripada||
:hasil (karena
1 -eq 1 && 1 -eq 0
dikelompokkan dan dengan demikian anggota ke-2||
):setidaknya untuk ksh , bash , zsh .
Jadi
[[ ]]
telah meningkatkan perilaku baik dari[ ]
operator shell langsung dan logis.sumber
[ x -o y ]
tidak harus mengevaluasi kedua belah pihak. Sementara GNUtest
atau[
builtin ofbash
do, Anda akan menemukannya denganstrace zsh -c '[ x -o -f /x ]'
itu[
tidak mencoba untuk stat ()/x
. Sama denganmksh
. Tetapi memang benar bahwa-o
dan-a
sangat rusak, tidak dapat digunakan dengan andal dan ditinggalkan oleh POSIX.[[...]]
,&&
memiliki prioritas lebih tinggi daripada||
, sementara di luar mereka memiliki prioritas yang sama. Bandingkanksh -c '[[ x || x && "" ]]'
vssh -c 'true || true && false'
[
/test
utilitas tidak memiliki==
operator. Operator kesetaraan adalah=
(perhatikan bahwa di dalam ksh[[...]]
,=
/==
bukan operator kesetaraan, tetapi yang cocok dengan pola).&&
lebih diutamakan di||
dalam[[...]]
(atau((...))
) tetapi tidak&&
dan||
operator shell.[[ x || y && z ]]
adalahx || (y && z)
sementarax || y && z
adalah(x || y) && z
(operator dievaluasi kiri ke kanan tanpa didahulukan). Mirip dengan bagaimana*
mendahului+
(1 + 2 * 3
adalah1 + (2 * 3)
) tapi+
dan-
memiliki prioritas yang sama.&&
telah didahulukan||
, maka itu seharusnyatrue || (true && false)
, bukannya(true || true) && false