Kesederhanaan elegan Bash tampaknya hilang di halaman manualnya yang besar.
Selain solusi hebat di atas, saya pikir saya akan mencoba memberi Anda lembar contekan tentang bagaimana bash mem-parsing dan menginterpretasikan pernyataan . Kemudian dengan menggunakan peta jalan ini saya akan menguraikan contoh-contoh yang disajikan oleh penanya untuk membantu Anda lebih memahami mengapa mereka tidak berfungsi sebagaimana dimaksud.
Catatan: Baris skrip Shell digunakan secara langsung. Input-line yang diketik adalah histori pertama yang diperluas.
Setiap baris bash pertama-tama ditandai , atau dengan kata lain dipotong menjadi apa yang disebut token . (Tokenisasi terjadi sebelum semua ekspansi lainnya, termasuk penjepit, tilde, parameter, perintah, aritmatika, proses, pemisahan kata, & ekspansi nama file.)
Token di sini berarti bagian dari jalur input dipisahkan (dibatasi) oleh salah satu karakter meta khusus ini:
space, - White space...
tab,
newline,
‘<’, - Redirection & piping...
‘|’,
‘>’
‘&’, - And/Both < | > | >> .or. &<file descriptor>
‘;’, - Command termination
‘(’, - Subshell, closed by - ‘)’
Bash menggunakan banyak karakter khusus lainnya tetapi hanya 10 yang menghasilkan token awal.
Namun karena meta-karakter ini juga terkadang harus digunakan dalam token, perlu ada cara untuk menghilangkan makna khusus mereka. Ini disebut melarikan diri. Lolos dilakukan baik dengan mengutip string dari satu atau lebih karakter, (yaitu 'xx..'
, "xx.."
), atau dengan mengawali karakter individu dengan garis miring, (yaitu \x
). (Ini sedikit lebih rumit dari ini karena tanda kutip juga perlu dikutip, dan karena tanda kutip ganda tidak mengutip semuanya, tetapi penyederhanaan ini akan berlaku untuk saat ini.)
Jangan bingung mengutip bash dengan gagasan mengutip string teks, seperti dalam bahasa lain. Apa yang ada di antara tanda kutip di bash bukanlah string, melainkan bagian dari baris input yang memiliki meta-karakter yang lolos sehingga mereka tidak membatasi token.
Perhatikan, ada perbedaan penting antara '
, dan "
, tapi itu untuk hari lain.
Meta-karakter unescaped yang tersisa kemudian menjadi pemisah token.
Sebagai contoh,
$ echo "x"'y'\g
xyg
$ echo "<"'|'\>
<|>
$ echo x\; echo y
x; echo y
Dalam contoh pertama ada dua token yang dihasilkan oleh pembatas ruang: echo
dan xyz
.
Demikian juga pada contoh ke-2.
Pada contoh ketiga titik koma adalah melarikan diri, jadi ada 4 token yang dihasilkan oleh pembatas ruang, echo
, x;
, echo
, dan y
. Token pertama kemudian dijalankan sebagai perintah, dan mengambil tiga token berikutnya sebagai input. Catatan 2 echo
tidak dieksekusi.
Yang penting untuk diingat adalah bahwa penampilan pertama bash untuk karakter melarikan diri ( '
, "
, dan \
), dan kemudian mencari pembatas meta-karakter yang tidak lolos, dalam urutan itu.
Jika tidak lolos maka 10 karakter khusus ini berfungsi sebagai token
pembatas. Beberapa dari mereka juga memiliki makna tambahan, tetapi pertama dan terutama, mereka adalah pembatas token.
Apa yang diharapkan grep
Dalam contoh di atas grep perlu token ini, grep
, string
, filename
.
Percobaan pertama adalah:
$ grep (lalu | di sana) xx
Dalam hal ini (
, )
dan |
adalah meta karakter unescaped dan berfungsi untuk membagi masukan ke token ini: grep
, (
, then
, |
, there
, )
, dan x.x
. grep ingin melihat grep
, then|there
dan x.x
.
Percobaan kedua adalah:
grep "(lalu | sana)" xx
Ini tokenizes ke grep
, (then|there)
, x.x
. Anda dapat melihat ini jika Anda menukar grep dengan gema:
echo "(lalu | di sana)" xx
(lalu | di sana) xx