Saran lama yang digunakan adalah mengutip dua kali ekspresi yang melibatkan $VARIABLE
, setidaknya jika seseorang ingin ditafsirkan oleh shell sebagai satu item tunggal, jika tidak, setiap ruang dalam konten $VARIABLE
akan membuang shell.
Saya mengerti, bagaimanapun, bahwa dalam versi shell yang lebih baru, kutip ganda tidak lagi selalu diperlukan (setidaknya untuk tujuan yang dijelaskan di atas). Misalnya, di bash
:
% FOO='bar baz'
% [ $FOO = 'bar baz' ] && echo OK
bash: [: too many arguments
% [[ $FOO = 'bar baz' ]] && echo OK
OK
% touch 'bar baz'
% ls $FOO
ls: cannot access bar: No such file or directory
ls: cannot access baz: No such file or directory
Di zsh
, di sisi lain, tiga perintah yang sama berhasil. Oleh karena itu, berdasarkan percobaan ini, tampaknya, di bash
, seseorang dapat menghilangkan tanda kutip ganda di dalam [[ ... ]]
, tetapi tidak di dalam [ ... ]
atau dalam argumen baris perintah, sedangkan, di zsh
, tanda kutip ganda dapat dihilangkan dalam semua kasus ini.
Tetapi menyimpulkan aturan umum dari contoh-contoh anekdotal seperti di atas adalah proposisi untung-untungan. Alangkah baiknya untuk melihat ringkasan kapan perlu mengutip ganda. Saya terutama tertarik pada zsh
, bash
, dan /bin/sh
.
SH_WORD_SPLIT
opsi.Jawaban:
Pertama, pisahkan zsh dari yang lain. Ini bukan masalah kerang tua vs modern: zsh berperilaku berbeda. Desainer zsh memutuskan untuk membuatnya tidak kompatibel dengan cangkang tradisional (Bourne, ksh, bash), tetapi lebih mudah digunakan.
Kedua, jauh lebih mudah menggunakan tanda kutip ganda sepanjang waktu daripada mengingat kapan mereka dibutuhkan. Mereka dibutuhkan sebagian besar waktu, jadi Anda harus belajar ketika mereka tidak dibutuhkan, bukan ketika mereka dibutuhkan.
Singkatnya, tanda kutip ganda diperlukan di mana pun daftar kata atau pola diharapkan . Mereka opsional dalam konteks di mana string mentah diharapkan oleh parser.
Apa yang terjadi tanpa tanda kutip
Perhatikan bahwa tanpa tanda kutip ganda, dua hal terjadi.
${foo}
, atau output dari perintah untuk substitusi perintah seperti$(foo)
) dibagi menjadi kata-kata di mana pun itu berisi spasi putih.Lebih tepatnya, hasil ekspansi dipecah pada setiap karakter yang muncul dalam nilai
IFS
variabel (karakter pemisah). Jika urutan karakter pemisah berisi spasi putih (spasi, tab atau baris baru), spasi putih dihitung sebagai karakter tunggal; pemisah non-spasi putih yang dipimpin, tertinggal, atau berulang mengarah ke bidang kosong. Misalnya, denganIFS=" :"
,:one::two : three: :four
menghasilkan bidang kosong sebelumone
, antaraone
dantwo
, dan (satu) antarathree
danfour
.\[*?
. Jika pola itu cocok dengan satu atau beberapa nama file, pola tersebut diganti dengan daftar nama file yang cocok.Ekspansi variabel yang tidak dikutip
$foo
secara bahasa dikenal sebagai "operator split + glob", berbeda dengan"$foo"
yang hanya mengambil nilai variabelfoo
. Hal yang sama berlaku untuk substitusi perintah:"$(foo)"
adalah substitusi perintah,$(foo)
adalah substitusi perintah yang diikuti oleh split + glob.Di mana Anda dapat menghilangkan tanda kutip ganda
Berikut adalah semua kasus yang dapat saya pikirkan dalam shell Bourne-style di mana Anda dapat menulis variabel atau substitusi perintah tanpa tanda kutip ganda, dan nilainya ditafsirkan secara harfiah.
Di sisi kanan penugasan.
Perhatikan bahwa Anda memerlukan tanda kutip ganda setelahnya
export
, karena ini adalah builtin biasa, bukan kata kunci. Ini hanya berlaku pada beberapa shell seperti dash, zsh (dalam emulasi sh), yash atau posh; bash dan ksh keduanya memperlakukanexport
secara khusus.Dalam sebuah
case
pernyataan.Perhatikan bahwa Anda perlu tanda kutip ganda dalam pola kasus. Pemisahan kata tidak terjadi dalam pola kasus, tetapi variabel yang tidak dikutip ditafsirkan sebagai pola sedangkan variabel yang dikutip ditafsirkan sebagai string literal.
Dalam kurung ganda. Kurung ganda adalah sintaks khusus shell.
Kecuali Anda memang membutuhkan tanda kutip ganda di mana pola atau ekspresi reguler diharapkan: di sisi kanan
=
atau==
atau!=
atau=~
.Anda memang perlu tanda kutip ganda seperti biasa dalam kurung tunggal
[ … ]
karena mereka adalah sintaksis shell biasa (ini adalah perintah yang kebetulan dipanggil[
). Lihat kurung tunggal atau gandaDalam pengalihan di shell POSIX non-interaktif (tidak
bash
, jugaksh88
).Beberapa shell, ketika interaktif, memperlakukan nilai variabel sebagai pola wildcard. POSIX melarang perilaku itu dalam cangkang non-interaktif, tetapi beberapa cangkang termasuk bash (kecuali dalam mode POSIX) dan ksh88 (termasuk ketika ditemukan sebagai (seharusnya) POSIX
sh
dari beberapa Unix komersial seperti Solaris) masih melakukannya di sana (bash
juga mencoba memisahkan dan pengalihan gagal kecuali bahwa perpecahan + globbing hasil persis satu kata), yang mengapa lebih baik untuk mengutip sasaran pengalihan dalamsh
naskah jika anda ingin mengubahnya menjadibash
naskah beberapa hari, atau menjalankannya pada sistem di manash
adalah tidak sesuai pada titik itu, atau mungkin bersumber dari shell interaktif.Di dalam ekspresi aritmatika. Bahkan, Anda harus meninggalkan tanda kutip agar variabel diuraikan sebagai ekspresi aritmatika.
Namun, Anda memang perlu tanda kutip di sekitar ekspansi aritmatika karena mereka tunduk pada pemisahan kata di sebagian besar kerang sebagai POSIX membutuhkan (!?).
Dalam subscript array asosiatif.
Variabel yang tidak dikutip dan substitusi perintah dapat berguna dalam beberapa situasi yang jarang terjadi:
$IFS
itu tidak dimodifikasi dan Anda ingin membaginya di karakter spasi.set -f
, setelIFS
ke karakter separator (atau biarkan sendiri untuk dibagi di whitespace), lalu lakukan ekspansi.Zsh
Di zsh, Anda dapat menghilangkan tanda kutip ganda sebagian besar kali, dengan beberapa pengecualian.
$var
tidak pernah mengembang ke beberapa kata, namun itu mengembang ke daftar kosong (sebagai lawan dari daftar yang mengandung satu kata, kosong) jika nilainyavar
adalah string kosong. Kontras:Demikian pula,
"${array[@]}"
memperluas ke semua elemen array, sementara$array
hanya memperluas ke elemen yang tidak kosong.The
@
bendera ekspansi parameter kadang-kadang membutuhkan tanda kutip ganda di sekitar seluruh substitusi:"${(@)foo}"
.Substitusi perintah mengalami pemisahan bidang jika tidak dikutip:
echo $(echo 'a'; echo '*')
cetakana *
(dengan satu spasi) sedangkanecho "$(echo 'a'; echo '*')"
mencetak string dua baris yang tidak dimodifikasi. Gunakan"$(somecommand)"
untuk mendapatkan output dari perintah dalam satu kata, tanpa akhir baris baru. Gunakan"${$(somecommand; echo _)%?}"
untuk mendapatkan output yang tepat dari perintah termasuk baris baru. Gunakan"${(@f)$(somecommand)}"
untuk mendapatkan larik garis dari output perintah.sumber
echo "$(("$expr"))"
man bash
dikatakan: Ekspresi diperlakukan seolah-olah berada dalam tanda kutip ganda, tetapi tanda kutip ganda di dalam tanda kurung tidak diperlakukan secara khusus.echo
. Mungkin ada baiknya mencoba membuat bahasa lebih eksplisit ("ketika string mentah diharapkan oleh parser", mungkin?)