Singkatnya, kutip semua hal di mana Anda tidak memerlukan shell untuk melakukan ekspansi token dan ekspansi wildcard.
Kutipan tunggal melindungi teks di antara mereka kata demi kata. Ini adalah alat yang tepat ketika Anda perlu memastikan bahwa shell tidak menyentuh tali sama sekali. Biasanya, ini adalah mekanisme pilihan mengutip ketika Anda tidak memerlukan interpolasi variabel.
$ echo 'Nothing \t in here $will change'
Nothing \t in here $will change
$ grep -F '@&$*!!' file /dev/null
file:I can't get this @&$*!! quoting right.
Kutipan ganda cocok ketika interpolasi variabel diperlukan. Dengan adaptasi yang sesuai, ini juga merupakan solusi yang baik ketika Anda membutuhkan tanda kutip tunggal dalam string. (Tidak ada cara langsung untuk melepaskan diri dari kutipan tunggal antara kutipan tunggal, karena tidak ada mekanisme melarikan diri di dalam kutipan tunggal - jika ada, mereka tidak akan mengutip sepenuhnya kata demi kata.)
$ echo "There is no place like '$HOME'"
There is no place like '/home/me'
Tidak ada kutipan yang cocok ketika Anda secara khusus meminta shell untuk melakukan pemisahan token dan / atau ekspansi wildcard.
Pemisahan Token;
$ words="foo bar baz"
$ for word in $words; do
> echo "$word"
> done
foo
bar
baz
Sebaliknya:
$ for word in "$words"; do echo "$word"; done
foo bar baz
(Loop hanya berjalan sekali, di atas string tunggal, yang dikutip.)
$ for word in '$words'; do echo "$word"; done
$words
(Loop hanya berjalan sekali, di atas string tunggal yang dikutip.)
Ekspansi wildcard:
$ pattern='file*.txt'
$ ls $pattern
file1.txt file_other.txt
Sebaliknya:
$ ls "$pattern"
ls: cannot access file*.txt: No such file or directory
(Tidak ada file bernama harfiah file*.txt
.)
$ ls '$pattern'
ls: cannot access $pattern: No such file or directory
(Tidak ada file bernama $pattern
, baik!)
Dalam istilah yang lebih konkret, apa pun yang mengandung nama file biasanya harus dikutip (karena nama file dapat berisi spasi putih dan karakter meta shell lainnya). Apa pun yang mengandung URL biasanya dikutip (karena banyak URL berisi karakter meta shell seperti ?
dan &
). Apa pun yang mengandung suatu regex biasanya harus dikutip (ditto ditto). Apa pun yang mengandung spasi putih signifikan selain spasi tunggal antara karakter non-spasi putih perlu dikutip (karena jika tidak, shell akan memasukkan ruang putih menjadi, secara efektif, spasi tunggal, dan memangkas spasi spasi apa pun yang mengarah atau tertinggal).
Ketika Anda tahu bahwa suatu variabel hanya dapat berisi nilai yang tidak mengandung karakter meta shell, mengutip adalah opsional. Jadi, tanda kutip $?
pada dasarnya baik-baik saja, karena variabel ini hanya dapat berisi satu angka. Namun, "$?"
ini juga benar, dan direkomendasikan untuk konsistensi dan kebenaran umum (meskipun ini adalah rekomendasi pribadi saya, bukan kebijakan yang diakui secara luas).
Nilai-nilai yang bukan variabel pada dasarnya mengikuti aturan yang sama, meskipun Anda kemudian bisa juga melarikan diri dari setiap metakarakter alih-alih mengutipnya. Sebagai contoh umum, URL dengan &
di dalamnya akan diurai oleh shell sebagai perintah latar belakang kecuali metacharacter lolos atau dikutip:
$ wget http://example.com/q&uack
[1] wget http://example.com/q
-bash: uack: command not found
(Tentu saja, ini juga terjadi jika URL berada dalam variabel yang tidak dikutip.) Untuk string statis, tanda kutip tunggal paling masuk akal, meskipun segala bentuk kutip atau melarikan diri berfungsi di sini.
wget 'http://example.com/q&uack' # Single quotes preferred for a static string
wget "http://example.com/q&uack" # Double quotes work here, too (no $ or ` in the value)
wget http://example.com/q\&uack # Backslash escape
wget http://example.com/q'&'uack # Only the metacharacter really needs quoting
Contoh terakhir juga menyarankan konsep lain yang bermanfaat, yang saya suka menyebutnya "mengutip jungkat-jungkit". Jika Anda perlu mencampur tanda kutip tunggal dan ganda, Anda dapat menggunakannya berdekatan. Misalnya, string yang dikutip berikut
'$HOME '
"isn't"
' where `<3'
"' is."
dapat disisipkan bersama kembali ke belakang, membentuk string panjang tunggal setelah tokenization dan penghapusan kutipan.
$ echo '$HOME '"isn't"' where `<3'"' is."
$HOME isn't where `<3' is.
Ini tidak terbaca dengan baik, tetapi ini adalah teknik yang umum dan karenanya baik untuk diketahui.
Selain itu, skrip biasanya tidak boleh digunakan ls
untuk apa pun. Untuk memperluas wildcard, cukup ... gunakan saja.
$ printf '%s\n' $pattern # not ``ls -1 $pattern''
file1.txt
file_other.txt
$ for file in $pattern; do # definitely, definitely not ``for file in $(ls $pattern)''
> printf 'Found file: %s\n' "$file"
> done
Found file: file1.txt
Found file: file_other.txt
(Pengulangan benar-benar berlebihan dalam contoh terakhir; printf
secara khusus berfungsi dengan baik dengan beberapa argumen stat
. Tetapi pengulangan pada pencocokan wildcard adalah masalah umum, dan sering dilakukan secara tidak benar.)
Variabel yang berisi daftar token untuk diulang atau wildcard untuk diekspansi lebih jarang terlihat, jadi kami terkadang menyingkat menjadi "mengutip segalanya kecuali Anda tahu persis apa yang Anda lakukan".