Pertanyaan saya berasal dari Bagaimana cara menyimpan ekspresi reguler dalam variabel shell menghindari masalah dengan mengutip karakter yang khusus untuk shell? .
Mengapa ada kesalahan:
$ [[ $a = a|b ]] bash: syntax error in conditional expression: unexpected token `|' bash: syntax error near `|b'
Di
[[ ... ]]
dalam operan kedua=
diharapkan menjadi pola globbing.Bukankah
a|b
pola globbing yang valid? Bisakah Anda menunjukkan aturan sintaks yang dilanggar?Beberapa komentar di bawah menunjukkan bahwa
|
diartikan sebagai pipa.Kemudian mengubah
=
untuk pola glob menjadi=~
untuk pola regex membuat|
pekerjaan$ [[ $a =~ a|b ]]
Saya belajar dari Learning Bash p180 di posting saya sebelumnya yang
|
diakui sebagai pipa pada awal interpretasi, bahkan sebelum langkah interpretasi lainnya (termasuk mengurai ekspresi kondisional dalam contoh). Jadi bagaimana bisa|
dikenali sebagai operator regex saat menggunakan=~
, tanpa dikenali sebagai pipa yang digunakan tidak valid, seperti halnya saat menggunakan=
? Itu membuat saya berpikir bahwa kesalahan sintaksis di bagian 1 tidak berarti|
ditafsirkan sebagai pipa.Setiap baris yang dibaca shell dari input standar atau skrip disebut pipeline; ini berisi satu atau lebih perintah yang dipisahkan oleh nol atau lebih karakter pipa (|). Untuk setiap pipa yang dibacanya, shell memecahnya menjadi perintah, mengatur I / O untuk pipa, kemudian melakukan hal berikut untuk setiap perintah (Gambar 7-1):
Terima kasih.
|
khusus) diaktifkan secara default di sisi kanan[[ $var = $pattern ]]
. Akan menarik untuk mengisolasishopt
konfigurasi versi dan opsi di mana perilaku ini terlihat - jika hanya ituextglob
yang aktif, baik dengan konfigurasi default atau eksplisit, well, kita ada di sana.pattern='a|b'
dan kemudian perluas tanda$pattern
kutip pada RHS.Jawaban:
Tidak ada alasan mengapa
Harus melaporkan kesalahan alih-alih menguji apakah $ a adalah
a|b
string, sementara[[ $a =~ a|b ]]
tidak mengembalikan kesalahan.Satu-satunya alasan adalah bahwa
|
umumnya (di luar dan di dalam[[ ... ]]
) karakter khusus. Di[[ $a =
posisi itu,bash
mengharapkan jenis token yang merupakan KATA normal seperti argumen atau target pengalihan dalam baris perintah shell normal (tetapi seolah-olahextglob
opsi 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:
Apakah
echo a
disalurkan keb
.a|b
bukan KATA , itu tiga token: aa
KATA ,|
token danb
KATA token.Saat digunakan di
[[ $a = a|b ]]
,bash
mengharapkan WORD yang didapat (a
), tetapi kemudian menemukan|
token yang tidak terduga yang menyebabkan kesalahan.Menariknya,
bash
tidak mengeluh dalam:Karena sekarang a
a
token diikuti oleh||
token diikuti olehb
, jadi diuraikan dengan cara yang sama seperti:Yang sedang menguji bahwa
$a
adalaha
atau bahwab
string non-kosong.Sekarang di:
bash
tidak 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 memastikana|b
adalah tunggal KATA . Tapi, sejak bash 3.2, jika Anda melakukannya:Itu tidak lagi cocok dengan
a|b
regexp tetapi terhadapa\|b
regexp. 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
bash
harus memperlakukan semua operator regexp yang diperluas yang biasanya karakter shell khusus seperti|
,(
,)
berbeda ketika parsing argumen dari=~
operator.Tetap, perhatikan itu sementara
sekarang bekerja,
tidak. Anda membutuhkan:
Yang dalam versi sebelumnya
bash
salah cocok dengan backslash. Yang itu sudah diperbaiki, tapiApakah tidak cocok di backslash seperti seharusnya misalnya. Karena
bash
gagal 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.Cocok dengan
a|b
Cocok regexp.Itu berarti
=~
dapat juga ditambahkan ke[
/test
perintah:(Juga bekerja di
yash
.=~
Kebutuhan dikutip dalamzsh
seperti=something
operator shell khusus di sana).bash 3.1 dulu berperilaku seperti
zsh
. Itu berubah di 3.2, mungkin untuk menyelaraskan denganksh93
(meskipunbash
shell yang pertama kali muncul dengan[[ =~ ]]
), tetapi Anda masih bisa melakukanBASH_COMPAT=31
ataushopt -s compat31
kembali ke perilaku sebelumnya (kecuali bahwa sementara[[ $a =~ a|b ]]
akan mengembalikan kesalahan dalambash
3.1, itu tidak lagi dibash -O compat31
dengan versi yang lebih barubash
).Semoga ini menjelaskan mengapa saya mengatakan aturannya membingungkan dan mengapa menggunakan:
membantu termasuk dengan portabilitas ke shell lain.
sumber
[[ $a = a|b ]]
.a|b
bukan KATA shell di sini, itua
,|
danb
token. Sukaecho a|b
tidak menghasilkana|b
atau tidak memperluasa|b
gumpalan, Anda perlu mengutip bahwa|
itu adalah karakter shell khusus yang tidak valid dalam konteks itu.[[ $a = (a|b) ]]
akan bekerja sepertiecho (a|b)
akan bekerja seperti(a|b)
operator wildcard zsh.Gumpalan standar ( "ekspansi nama file") adalah:
*
,?
, dan[ ... ]
.|
bukan operator glob yang valid dalam pengaturan standar (non-extglob).Mencoba:
sumber
|
diintepretasikan secara harfiah? Mengapa ada kesalahan sintaksis?|
bukankah operator glob, jadi tidak|
ditafsirkan secara literal tanpa dikutip? Jadi mengapa ada kesalahan sintaksis?|
adalah karakter kontrol; itu tidak pernah diperlakukan sebagai karakter literal dengan cara yang sama seperti huruf atau angka.[[ $a = a
bukan perintah yang valid yang outputnya dapat disalurkan ke proses lain (setidaknya itulah yang dipikirkan shell yang Anda coba lakukan).Jika Anda ingin pencocokan regex, tesnya adalah:
sumber