Ini adalah kasus sudut yang sangat tidak jelas yang dapat dianggap sebagai bug dalam cara tes [
bawaan ditetapkan; Namun, itu cocok dengan perilaku [
biner aktual yang tersedia di banyak sistem. Sejauh yang saya tahu, itu hanya mempengaruhi kasus-kasus tertentu dan variabel yang memiliki nilai yang cocok dengan [
operator yang seperti (
, !
, =
, -e
, dan sebagainya.
Biarkan saya jelaskan alasannya, dan bagaimana cara mengatasinya dalam shell Bash dan POSIX.
Penjelasan:
Pertimbangkan yang berikut ini:
x="("
[ "$x" = "(" ] && echo yes || echo no
Tidak masalah; hasil di atas tidak ada kesalahan, dan output yes
. Beginilah cara kami mengharapkan barang bekerja. Anda dapat mengubah string perbandingan menjadi '1'
jika Anda suka, dan nilainya x
, dan itu akan berfungsi seperti yang diharapkan.
Perhatikan bahwa /usr/bin/[
biner yang sebenarnya berperilaku dengan cara yang sama. Jika Anda menjalankan mis. '/usr/bin/[' '(' = '(' ']'
Tidak ada kesalahan, karena program dapat mendeteksi bahwa argumen terdiri dari operasi perbandingan string tunggal.
Bug terjadi ketika kita dan dengan ekspresi kedua. Tidak masalah apa ekspresi kedua, asalkan valid. Sebagai contoh,
[ '1' = '1' ] && echo yes || echo no
output yes
, dan jelas merupakan ekspresi yang valid; tapi, jika kita gabungkan keduanya,
[ "$x" = "(" -a '1' = '1' ] && echo yes || echo no
Bash menolak ekspresi jika dan hanya jika x
ada (
atau !
.
Jika kita menjalankan di atas menggunakan [
program yang sebenarnya , yaitu
'/usr/bin/[' "$x" = "(" -a '1' = '1' ] && echo yes || echo no
kesalahan akan dapat dimengerti: karena shell melakukan substitusi variabel, /usr/bin/[
biner hanya menerima parameter (
=
(
-a
1
=
1
dan terminating ]
, itu dimengerti gagal untuk menguraikan apakah tanda kurung buka memulai sub-ekspresi atau tidak, ada dan operasi yang terlibat. Tentu, menguraikannya sebagai dua perbandingan string adalah mungkin, tetapi melakukannya dengan rakus seperti itu dapat menyebabkan masalah ketika diterapkan pada ekspresi yang tepat dengan sub-ekspresi yang diurung.
Masalahnya, sebenarnya, shell [
built-in berperilaku dengan cara yang sama, seolah-olah itu memperluas nilai x
sebelum memeriksa ekspresi.
(Ambiguitas ini, dan yang lainnya terkait dengan ekspansi variabel, adalah alasan besar mengapa Bash diimplementasikan dan sekarang merekomendasikan penggunaan [[ ... ]]
ekspresi tes sebagai gantinya.)
Penanganannya sepele, dan sering terlihat dalam skrip menggunakan sh
shell yang lebih lama . Anda menambahkan karakter "aman", sering x
, di depan string (kedua nilai dibandingkan), untuk memastikan ekspresi diakui sebagai perbandingan string:
[ "x$x" = "x(" -a "x$y" = "x1" ]
[[ "$x" = '1' && "$y" = '1' ]]