Tidak ada alasan mengapa
[[ $a = a|b ]]
Harus melaporkan kesalahan alih-alih menguji apakah $ a adalah a|bstring, sementara [[ $a =~ a|b ]]tidak mengembalikan kesalahan.
Satu-satunya alasan adalah bahwa |umumnya (di luar dan di dalam [[ ... ]]) karakter khusus. Di [[ $a =posisi itu, bashmengharapkan jenis token yang merupakan KATA normal seperti argumen atau target pengalihan dalam baris perintah shell normal (tetapi seolah-olah extglobopsi telah diaktifkan sejak bash 4.1).
(oleh WORD di sini, saya merujuk pada a kata dalam tata bahasa shell hipotetis seperti yang dijelaskan oleh spesifikasi POSIX , itu adalah sesuatu yang shell akan parse sebagai salah satu token dalam baris perintah shell sederhana, bukan definisi lain dari kata-kata seperti bahasa Inggris salah satu dari urutan huruf atau urutan karakter non-spasi. foo"bar baz", $(echo x y), dua seperti WORD s).
Dalam baris perintah shell normal:
echo a|b
Apakah echo adisalurkan ke b. a|bbukan KATA , itu tiga token: aa KATA , |token dan b KATA token.
Saat digunakan di [[ $a = a|b ]] , bashmengharapkan WORD yang didapat ( a), tetapi kemudian menemukan |token yang tidak terduga yang menyebabkan kesalahan.
Menariknya, bashtidak mengeluh dalam:
[[ $a = a||b ]]
Karena sekarang a a token diikuti oleh ||token diikuti oleh b, jadi diuraikan dengan cara yang sama seperti:
[[ $a = a || b ]]
Yang sedang menguji bahwa $aadalah aatau bahwa bstring non-kosong.
Sekarang di:
[[ $a =~ a|b ]]
bashtidak dapat memiliki aturan penguraian yang sama. Memiliki aturan penguraian yang sama akan berarti bahwa di atas akan memberikan kesalahan dan bahwa seseorang perlu mengutip bahwa |untuk memastikan a|badalah tunggal KATA . Tapi, sejak bash 3.2, jika Anda melakukannya:
[[ $a =~ 'a|b' ]]
Itu tidak lagi cocok dengan a|bregexp tetapi terhadap a\|bregexp. Artinya, mengutip shell memiliki efek samping menghilangkan makna khusus dari operator regexp. Ini fitur, jadi perilakunya mirip dengan yang [[ $a = "?" ]]ada, tetapi pola wildcard (digunakan dalam[[ $a = pattern ]] ) shell WORDS (digunakan dalam gumpalan misalnya), sedangkan regexps tidak.
Jadi bashharus memperlakukan semua operator regexp yang diperluas yang biasanya karakter shell khusus seperti| , (, )berbeda ketika parsing argumen dari =~operator.
Tetap, perhatikan itu sementara
[[ $a =~ (ab)*c ]]
sekarang bekerja,
[[ $a =~ [)}] ]]
tidak. Anda membutuhkan:
[[ $a =~ [\)}] ]]
[[ $a =~ [')'}] ]]
Yang dalam versi sebelumnya bash salah cocok dengan backslash. Yang itu sudah diperbaiki, tapi
[[ $a =~ [^]')'] ]]
Apakah tidak cocok di backslash seperti seharusnya misalnya. Karena bashgagal menyadari bahwa )ada di dalam kurung, maka lolos )ke menghasilkan [^]\)]regexp yang cocok dengan karakter apa pun tetapi ],\ dan ).
ksh93 memiliki bug jauh lebih buruk di bagian depan itu.
Dalam zsh, itu adalah kata shell normal yang diharapkan dan mengutip operator regexp tidak mempengaruhi arti dari operator regexp.
[[ $a =~ 'a|b' ]]
Cocok dengan a|bCocok regexp.
Itu berarti =~dapat juga ditambahkan ke [/ testperintah:
[ "$a" '=~' 'a|b' ]
test "$a" '=~' 'a|b'
(Juga bekerja di yash. =~Kebutuhan dikutip dalamzsh seperti =somethingoperator shell khusus di sana).
bash 3.1 dulu berperilaku seperti zsh. Itu berubah di 3.2, mungkin untuk menyelaraskan dengan ksh93(meskipun bashshell yang pertama kali muncul dengan [[ =~ ]]), tetapi Anda masih bisa melakukan BASH_COMPAT=31atau shopt -s compat31kembali ke perilaku sebelumnya (kecuali bahwa sementara [[ $a =~ a|b ]]akan mengembalikan kesalahan dalam bash3.1, itu tidak lagi dibash -O compat31 dengan versi yang lebih baru bash).
Semoga ini menjelaskan mengapa saya mengatakan aturannya membingungkan dan mengapa menggunakan:
[[ $a =~ $var ]]
membantu termasuk dengan portabilitas ke shell lain.
|khusus) diaktifkan secara default di sisi kanan[[ $var = $pattern ]]. Akan menarik untuk mengisolasishoptkonfigurasi versi dan opsi di mana perilaku ini terlihat - jika hanya ituextglobyang aktif, baik dengan konfigurasi default atau eksplisit, well, kita ada di sana.