Ini saatnya untuk memecahkan teka-teki yang telah mengganggu saya selama bertahun-tahun ...
Saya telah bertemu ini dari waktu ke waktu dan berpikir inilah jalan yang harus ditempuh:
$(comm "$(arg)")
Dan pikir pandangan saya sangat didukung oleh pengalaman. Tapi saya tidak begitu yakin lagi. Shellcheck tidak bisa mengambil keputusan juga. Keduanya:
"$(dirname $0)"/stop.bash
^-- SC2086: Double quote to prevent globbing and word splitting.
Dan:
$(dirname "$0")/stop.bash
^-- SC2046: Quote this to prevent word splitting.
Apa logika di baliknya?
(Ini Shellcheck versi 0.4.4, btw.)
bash
quoting
command-substitution
Tomasz
sumber
sumber
"$(dirname "$0")"/stop.bash
:? Tampaknya berhasil ... Apa ceritanya?shell_level_1 $(shell_level_2) shell_level_1
ketika Anda berada di dalam$(....)
Anda memasukkan "sublevel" shell, TETAPI Anda dapat menulis di dalamnya seolah-olah Anda berada di tingkat dasar (yaitu, Anda dapat langsung menulis"
bukan\"
, dll). mis:touch "/tmp/a file" ; echo "its size is: $(find "/tmp/a file" -ls | awk '{print $5}) ..." : if you used backticks you'd have to
temukan \ "/ tmp / file \" `danprint \$5
. Tanpa$(...)
perlu: shell beradaptasi ke level yang baru dan Anda dapat menulis langsung seolah-olah penerjemah Anda sekarang berada di level itu juga.Jawaban:
Anda harus menggunakan
"$(somecmd "$file")"
.Tanpa tanda kutip, jalan dengan spasi akan terpecah dalam argumen untuk
somecmd
, dan itu akan menargetkan file yang salah. Jadi Anda perlu penawaran di dalam.Setiap spasi dalam output
somecmd
juga akan menyebabkan pemisahan, jadi Anda perlu tanda kutip di bagian luar seluruh substitusi perintah.Kutipan di dalam substitusi perintah tidak berpengaruh pada kutipan di luarnya. Manual referensi Bash sendiri tidak terlalu jelas tentang hal ini, tetapi BashGuide secara eksplisit menyebutkannya . The teks dalam POSIX juga memerlukan itu, sebagai "script shell yang valid" yang diizinkan di dalam
$(...)
:Contoh:
Sebuah. Tidak ada kutipan,
dirname
memproses keduanya./space
danhere/foo
:b. Kutipan di dalam,
dirname
proses./space here/foo
, memberi./space here
, yang terbagi dua:c. Kutipan di luar,
dirname
memproses keduanya./space
danhere/foo
, output pada baris yang terpisah, tetapi sekarang dua baris membentuk argumen tunggal :d. Kutipan baik di dalam maupun di luar, ini memberikan jawaban yang benar:
(Itu mungkin akan lebih sederhana jika
dirname
hanya memproses argumen pertama, tetapi itu tidak akan menunjukkan perbedaan antara kasus a dan c.)Perhatikan bahwa dengan
dirname
(dan mungkin orang lain) Anda juga perlu menambahkan--
, untuk mencegah nama file tidak diambil sebagai opsi jika terjadi mulai dengan tanda hubung, jadi gunakan"$(dirname -- "$file")"
.sumber
$( )
menciptakan konteks baru, sehingga tanda kutip di dalamnya independen dari tanda kutip di luarnya. Dan Anda umumnya ingin mengutip dalam kedua konteks.