Saya menggunakan GNU bash
4.3.48
. Pertimbangkan dua perintah berikut yang hanya berbeda dengan satu tanda dolar.
Perintah 1:
echo "(echo " * ")"
Perintah 2:
echo "$(echo " * ")"
Outputnya masing-masing
(echo test.txt ppcg.sh )
dan
*
Jadi jelas dalam kasus pertama *
adalah globbed, yang berarti bahwa tanda kutip pertama pergi dengan yang kedua untuk membentuk pasangan, dan yang ketiga dan keempat membentuk pasangan yang lain.
Dalam kasus kedua *
ini tidak menggumpal, dan ada tepat dua ruang ekstra dalam output, satu sebelum asterisk dan satu setelah, yang berarti bahwa tanda kutip kedua berjalan dengan yang ketiga, dan yang pertama pergi dengan yang keempat.
Apakah ada kasus lain selain $()
konstruksi yang tanda kutipnya tidak cocok dengan yang berikutnya, tetapi malah bersarang? Apakah perilaku ini didokumentasikan dengan baik dan jika ya, di mana saya dapat menemukan dokumen yang sesuai?
Jawaban:
Setiap konstruk bersarang yang dapat diinterpolasi di dalam string dapat memiliki string lebih lanjut di dalamnya: mereka diurai seperti skrip baru, hingga penanda penutup, dan bahkan dapat bersarang dalam beberapa level. Semua bar salah satunya dimulai dengan a
$
. Semuanya didokumentasikan dalam kombinasi dari spesifikasi bahasa perintah manual Bash dan POSIX shell.Ada beberapa kasus konstruksi ini:
Perintahkan substitusi dengan
$( ... )
, seperti yang Anda temukan. POSIX menentukan perilaku ini :Kutipan adalah bagian dari skrip shell yang valid, jadi mereka diizinkan dengan makna normalnya.
`
juga digunakan.Elemen "kata" dari contoh substitusi parameter lanjutan seperti
${parameter:-word}
. The definisi "kata" adalah :- yang mencakup teks kutipan dan bahkan kutipan campuran
a"b"c'd'e
- meskipun perilaku sebenarnya dari ekspansi sedikit lebih liberal dari itu, dan misalnya${x:-hello world}
berfungsi juga.Ekspansi aritmatika dengan
$(( ... ))
, meskipun sebagian besar tidak berguna di sana (tetapi Anda juga dapat membuat substitusi perintah atau ekspansi variabel, dan kemudian memiliki tanda kutip yang berguna di dalamnya). POSIX menyatakan bahwa :jadi perilaku ini secara eksplisit diperlukan. Itu berarti
echo "abc $((4 "*" 5))"
tidak berhitung, bukan globbing.Perhatikan bahwa
$[ ... ]
ekspansi aritmatika gaya lama tidak diperlakukan dengan cara yang sama: kutipan akan menjadi kesalahan jika muncul, terlepas dari apakah ekspansi tersebut dikutip atau tidak. Formulir ini tidak didokumentasikan sama sekali, dan tidak dimaksudkan untuk digunakan.$"..."
, yang sebenarnya menggunakan"
elemen inti.$"
diperlakukan sebagai satu unit.Ada satu kasus bersarang lebih lanjut yang mungkin tidak Anda harapkan, tidak melibatkan tanda kutip, yang dengan ekspansi penjepit :
{a,b{c,d},e}
memperluas ke "a bc bd e".${x:-a{b,c}d}
tidak tidak sarang, namun; itu diperlakukan sebagai substitusi parameter yang memberi "a{b,c
", diikuti oleh "d}
". Itu juga didokumentasikan :Sebagai aturan umum, semua konstruksi yang dibatasi mengurai tubuh mereka secara independen dari konteks sekitarnya (dan pengecualian diperlakukan sebagai bug ). Intinya, saat melihat
$(
kode substitusi perintah hanya meminta parser untuk mengkonsumsi apa yang bisa dari tubuh seolah-olah itu adalah program baru, dan kemudian memeriksa bahwa penanda penghentian yang diharapkan (yang tidak terhapus)
atau))
atau}
) muncul setelah sub-parser berjalan dari hal-hal yang dapat dikonsumsi.Jika Anda berpikir tentang fungsi a parser keturunan-rekursif , itu hanya rekursi sederhana untuk kasus dasar. Ini sebenarnya lebih mudah dilakukan daripada sebaliknya, begitu Anda mendapatkan interpolasi string sama sekali. Terlepas dari teknik parsing yang mendasarinya, cangkang yang mendukung konstruksi ini memberikan hasil yang sama.
Anda dapat membuat sarang mengutip sebanyak yang Anda suka melalui konstruksi ini dan itu akan berfungsi seperti yang diharapkan. Tidak ada yang akan bingung dengan melihat kutipan di tengah; sebaliknya, itu akan menjadi awal dari string yang dikutip baru dalam konteks interior.
sumber
"blah/blah\n$(cat "${tmpdir}/${filename}.jpdf")"
, mengapa kutipan ganda kedua bukan akhir dari kutipan ganda pertama (seperti yang ditunjukkan oleh penyorotan sintaks pada balasan Anda), tetapi awal dari sebuah string di dalam$(...)
? Apakah karena pengurai bash adalah top-down, bukan bottom-up?"${var-"foo"}"
(echo "${-+"*"}"
sama sepertiecho *
dalam shell Bourne atau Korn misalnya) dan perilaku akan dibuat jelas tidak ditentukan dalam versi standar berikutnya . Lihat juga diskusi di mail-archive.com/[email protected]/msg00167.htmlMungkin melihat dua contoh dengan
printf
(bukannyaecho
) akan membantu:Mencetak
(echo
(kata pertama, termasuk spasi tambahan), beberapa file, dan kata penutup)
.Tanda kurung hanyalah bagian dari string yang dikutip
(echo
.Tanda bintang (sekarang tidak dikutip, karena dua tanda kutip ganda dipasangkan) diperluas sebagai gumpalan ke daftar file yang cocok.
Dan kemudian, tanda kurung tutup.
Namun, perintah kedua Anda berfungsi sebagai berikut:
The
$
dimulai substitusi perintah. Itu dimulai kutipan baru.Tanda bintang dikutip
" * "
dan itulah yang dihasilkan oleh perintah (di sini adalah perintah dan bukan string yang dikutip)echo
. Akhirnya,printf
format ulang*
dan cetak sebagai< * >
.sumber