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.
- Pertama, hasil ekspansi (nilai variabel untuk substitusi parameter seperti
${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, dengan IFS=" :"
, :one::two : three: :four
menghasilkan bidang kosong sebelum one
, antara one
dan two
, dan (satu) antara three
dan four
.
- Setiap bidang yang dihasilkan dari pemisahan ditafsirkan sebagai bola (pola wildcard) jika berisi salah satu karakter
\[*?
. 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 variabel foo
. 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.
var=$stuff
a_single_star=*
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 memperlakukan export
secara khusus.
export VAR="$stuff"
Dalam sebuah case
pernyataan.
case $var in …
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.
a_star='a*'
case $var in
"$a_star") echo "'$var' is the two characters a, *";;
$a_star) echo "'$var' begins with a";;
esac
Dalam kurung ganda. Kurung ganda adalah sintaks khusus shell.
[[ -e $filename ]]
Kecuali Anda memang membutuhkan tanda kutip ganda di mana pola atau ekspresi reguler diharapkan: di sisi kanan =
atau ==
atau !=
atau =~
.
a_star='a*'
if [[ $var == "$a_star" ]]; then echo "'$var' is the two characters a, *"
elif [[ $var == $a_star ]]; then echo "'$var' begins with a"
fi
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 ganda
Dalam pengalihan di shell POSIX non-interaktif (tidak bash
, juga ksh88
).
echo "hello world" >$filename
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 dalam sh
naskah jika anda ingin mengubahnya menjadi bash
naskah beberapa hari, atau menjalankannya pada sistem di mana sh
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.
expr=2*2
echo "$(($expr))"
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.
typeset -A a
i='foo bar*qux'
a[foo\ bar\*qux]=hello
echo "${a[$i]}"
Variabel yang tidak dikutip dan substitusi perintah dapat berguna dalam beberapa situasi yang jarang terjadi:
- Ketika nilai variabel atau output perintah terdiri dari daftar pola glob dan Anda ingin memperluas pola ini ke daftar file yang cocok.
- Ketika Anda tahu bahwa nilainya tidak mengandung karakter wildcard,
$IFS
itu tidak dimodifikasi dan Anda ingin membaginya di karakter spasi.
- Saat Anda ingin membagi nilai pada karakter tertentu: nonaktifkan globbing with
set -f
, setel IFS
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 nilainya var
adalah string kosong. Kontras:
var=
print -l $var foo # prints just foo
print -l "$var" foo # prints an empty line, then foo
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 '*')
cetakan a *
(dengan satu spasi) sedangkan echo "$(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.
SH_WORD_SPLIT
opsi.