Mengapa ekspansi variabel bash mempertahankan tanda kutip?

12
> echo "hi"
hi
> VAR='echo "hi"'
> $VAR
"hi"

Mengapa output dari perintah di atas berbeda?

Hal serupa terjadi dengan kutipan tunggal:

> VAR="echo 'hi'"
> $VAR
> 'hi'
Cory Klein
sumber
6
Harap jangan biasakan menanamkan potongan skrip yang dapat dieksekusi dalam variabel. Ini cenderung paling sulit dan evalmerupakan ladang ranjau dari lubang keamanan potensial yang harus Anda tapak dengan hati
jw013
@ jw013 Poin bagus dan artikel bagus. Saya suka kutipan "Variabel menyimpan data, fungsi menyimpan kode." dari tautan pertama, tetapi untuk penggunaan saya, data yang diberikan ke suatu fungsi (dalam hal ini, at) adalah kode. Adakah tips tentang cara yang lebih aman untuk mengatur / mengumpulkan kode yang akan diberikan at?
Cory Klein
atmengambil shsintaks sebagai input. Jadi menghasilkan input untuk atberarti menghasilkan shsintaks yang valid dan dikutip dengan benar dari input sewenang-wenang, yang tidak sepele, jadi saya akan mencoba menghindarinya jika memungkinkan. Akan sangat membantu jika Anda bisa memberikan sedikit lebih banyak detail tentang apa yang ingin Anda capai.
jw013
Maaf, saya tidak ingin mengalihkan perhatian dengan terlalu banyak detail, tetapi apa yang saya lakukan tidak terlalu rumit, IMO. Saya membuat skrip yang membutuhkan "waktu" dan "pesan". Itu kemudian berjalan atuntuk "waktu" yang diberikan, dan memberitahu atuntuk menjalankan perintah dzen2. dzen2mengambil "pesan" dari stdin, dan juga menggunakan beberapa parameter statis lainnya. Kesulitannya adalah saya perlu menyalurkan parameter "pesan" dari pengguna ke dzen2perintah, tapi saya tidak benar-benar menjalankan dzen2sendiri, saya mengatakan atuntuk melakukannya.
Cory Klein
1
superuser.com/questions/360966/… || stackoverflow.com/questions/7454526/…
Ciro Santilli 新疆 改造 中心 法轮功 六四 事件

Jawaban:

16

Pasangan penawaran tambahan hanya akan dikonsumsi oleh langkah evaluasi tambahan. Misalnya dipaksa oleh eval:

bash-4.2$ VAR='echo "hi"'

bash-4.2$ $VAR
"hi"

bash-4.2$ eval $VAR
hi

Tetapi umumnya adalah ide yang buruk untuk menempatkan perintah dengan parameter dalam satu string. Gunakan array sebagai gantinya:

bash-4.2$ VAR=(echo "hi")

bash-4.2$ "${VAR[@]}"
hi
manatwork
sumber
1
Penting juga untuk dicatat bahwa kutipan dievaluasi secara berbeda; tanda kutip ganda (") memungkinkan evaluasi string terlampir, tanda kutip tunggal (') mencetak string sebagai literal. Contoh: "$(ls)"dan '$(ls)'. Ini adalah alasan mengapa kutipan muncul dalam contoh pertanyaan asli.
Joseph Kern
Array juga merupakan sumber masalah. Kode milik fungsi, data ke variabel. Contoh yang Anda sajikan bekerja hanya karena tanda kutip dihapus dalam pemisahan array. A printf '<%s> ' "${VAR[@]}"akan menunjukkan bahwa kutipan sudah dihapus. Jika Anda menetapkan VAR sebagai VAR=(echo \"hi\")benar-benar memiliki tanda kutip, masalah yang sama muncul lagi, $ ${VAR[@]}akan dicetak"hi"
9

Penghapusan kutipan hanya terjadi pada kata-kata input asli, bukan pada hasil ekspansi. Kutipan yang merupakan bagian dari variabel yang diperluas tidak tersentuh.

jw013
sumber
2

Jika Anda mundur sedikit, Anda dapat melihat mengapa substitusi variabel benar-benar harus mempertahankan tanda kutip.

Inti dari kutipan dalam shell Unix / Linux / BSD adalah untuk menjaga potongan-potongan string bersama yang jika tidak akan diuraikan sebagai beberapa string. Karena secara default shell menggunakan spasi sebagai pemisah token, string dengan spasi (seperti "satu dua tiga") jika tidak dikutip atau lolos, akan diurai menjadi 3 string: "satu", "dua" dan "tiga".

Jika seorang programmer menginginkan sebuah string dengan nilai beberapa variabel diinterpolasi:

VAR=two
STRING="one $VAR three"

shell harus benar-benar tidak menghapus tanda kutip: string yang berisi spasi akan diuraikan sebagai 3 string yang lebih kecil.

Bruce Ediger
sumber