Dalam pertanyaan ini seseorang melaporkan masalah menggunakan dokumen di sini dengan kata pembatas yang dikutip di dalam $(...)
substitusi perintah , di mana backslash \
di akhir baris di dalam dokumen memicu kelanjutan baris baru yang bergabung , sedangkan dokumen yang sama di sini di luar substitusi perintah berfungsi seperti yang diharapkan .
Berikut ini contoh dokumen yang disederhanakan:
cat <<'EOT'
abc ` def
ghi \
jkl
EOT
Ini termasuk satu backtick dan satu backslash di akhir baris. Pembatas dikutip, jadi tidak ada ekspansi yang terjadi di dalam tubuh. Dalam semua Bourne-sama saya dapat menemukan ini menampilkan konten kata demi kata. Jika saya meletakkan dokumen yang sama di dalam substitusi perintah sebagai berikut:
x=$(cat <<'EOT'
abc ` def
ghi \
jkl
EOT
)
echo "$x"
maka mereka tidak lagi berperilaku identik:
dash
,ash
,zsh
,ksh93
, BusyBoxash
,mksh
dan SunOS 5.10 POSIXsh
semua memberikan isi persis dari dokumen, seperti sebelumnya.- Bash 3.2 memberikan kesalahan sintaksis untuk backtick yang tak tertandingi. Dengan backtick yang cocok, ia mencoba menjalankan konten sebagai perintah.
- Bash 4.3 runtuh "ghi" dan "jkl" ke satu baris, tetapi tidak memiliki kesalahan. The
--posix
pilihan tidak mempengaruhi ini. Kusalananda memberitahuku (terima kasih!) Yangpdksh
berlaku sama .
Dalam pertanyaan awal, saya mengatakan ini adalah bug di parser Bash. Apakah itu? [Perbarui: ya ] Teks yang relevan dari POSIX (semua dari definisi Bahasa Perintah Shell) yang dapat saya temukan adalah:
- §2.6.3 Substitusi Perintah :
Dengan formulir $ (perintah), semua karakter yang mengikuti tanda kurung terbuka ke tanda kurung penutup yang cocok merupakan perintah. Setiap skrip shell yang valid dapat digunakan untuk perintah , kecuali skrip yang hanya terdiri dari pengalihan yang menghasilkan hasil yang tidak ditentukan.
- §2.7.4 Dokumen-Berikut :
Jika ada bagian kata yang dikutip, pembatas akan dibentuk dengan melakukan penghapusan kutipan pada kata , dan baris dokumen di sini tidak akan diperluas.
- §2.2.1 Karakter Escape (Backslash) :
Jika <newline> mengikuti <backslash>, shell harus menafsirkan ini sebagai kelanjutan garis. <backslash> dan <newline> harus dihapus sebelum memisahkan input menjadi token.
- §2.3 Pengakuan Token :
Ketika token io_here telah dikenali oleh tata bahasa (lihat Tata Bahasa Shell ), satu atau lebih dari baris berikutnya segera mengikuti token NEWLINE berikutnya membentuk badan dari satu atau lebih dokumen di sini dan harus diuraikan sesuai dengan aturan di sini- dokumen .
Ketika tidak memproses io_here , shell harus memecah inputnya menjadi token dengan menerapkan aturan pertama yang berlaku di bawah ini ke karakter berikutnya dalam inputnya. ...
...
- Jika karakter saat ini adalah <backslash>, tanda kutip tunggal, atau tanda kutip ganda dan tidak dikutip, itu akan mempengaruhi mengutip untuk karakter selanjutnya hingga akhir teks yang dikutip. Aturan untuk mengutip adalah sebagaimana dijelaskan dalam Mengutip . Selama pengenalan token, tidak ada pergantian yang benar-benar dilakukan, dan token hasil harus berisi persis karakter yang muncul dalam input (kecuali untuk <newline> bergabung), tidak dimodifikasi, termasuk setiap kutipan atau operator substitusi yang disematkan atau dilampirkan, antara dan akhir dari teks yang dikutip.
Penafsiran saya tentang ini adalah bahwa semua karakter setelah $(
hingga terminasi )
terdiri dari skrip shell, kata demi kata; dokumen di sini muncul, jadi di sini-pemrosesan dokumen terjadi alih-alih tokenisasi biasa; dokumen di sini kemudian memiliki pembatas yang dikutip, yang artinya bahwa isinya diproses secara kata demi kata; dan karakter pelarian tidak pernah masuk ke dalamnya. Saya dapat melihat argumen, bahwa kasus ini tidak ditangani, dan kedua perilaku tersebut diperbolehkan. Mungkin saja saya juga melewatkan beberapa teks yang relevan di suatu tempat.
- Apakah situasi ini diperjelas di tempat lain?
- Apa yang harus diandalkan oleh skrip portabel (secara teori)?
- Apakah perlakuan khusus diberikan oleh salah satu dari cangkang ini (Bash 3.2 / Bash 4.3 / orang lain) diamanatkan oleh standar? Terlarang? Diizinkan?
echo "$x"
, tetapi segala cara memeriksa variabel berfungsi. Saya telah mengedit baris itu ke bawah.
$(...)
dengan apa pun keluaran itu ... Sekarang, saat menjalankan perintah dalam contoh Anda dalam subkulit (dalam bash
) itu memang menampilkan hasil yang diharapkan. Hanya ketika mengubahnya menjadi substitusi perintah maka itu akan runtuh "ghi" dan "jkl". Jadi ini bug imo