Aturan umum:kutip jika itu bisa kosong atau mengandung spasi (atau benar-benar spasi putih) atau karakter khusus (wildcard). Tidak mengutip string dengan spasi sering menyebabkan shell memecah satu argumen menjadi banyak.
$?
tidak perlu tanda kutip karena ini adalah nilai numerik. Apakah $URL
membutuhkannya tergantung pada apa yang Anda izinkan di sana dan apakah Anda masih menginginkan argumen jika kosong.
Saya cenderung selalu mengutip string hanya karena kebiasaan karena lebih aman seperti itu.
Singkatnya, kutip semua hal di mana Anda tidak memerlukan shell untuk melakukan pemisahan token dan perluasan karakter pengganti.
Kutipan tunggal melindungi teks di antara mereka kata demi kata. Ini adalah alat yang tepat ketika Anda perlu memastikan bahwa cangkang tidak menyentuh tali sama sekali. Biasanya, ini adalah mekanisme kutipan pilihan saat 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 saat Anda membutuhkan tanda kutip tunggal dalam string. (Tidak ada cara langsung untuk keluar dari tanda kutip tunggal di antara tanda kutip tunggal, karena tidak ada mekanisme keluar di dalam tanda kutip 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 tanda kutip yang sesuai jika Anda secara khusus memerlukan shell untuk melakukan pemisahan token dan/atau perluasan karakter pengganti.
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
(Perulangan hanya berjalan sekali, melalui string tunggal yang dikutip.)
$ for word in '$words'; do echo "$word"; done
$words
(Perulangan hanya berjalan sekali, melalui string kutip tunggal literal.)
Ekspansi karakter pengganti:
$ 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 yang bernama 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 berisi nama file biasanya harus dikutip (karena nama file dapat berisi spasi putih dan karakter meta shell lainnya). Apa pun yang berisi URL biasanya harus dikutip (karena banyak URL berisi karakter meta shell seperti ?
dan &
). Apa pun yang mengandung regex biasanya harus dikutip (ditto ditto). Apa pun yang mengandung spasi signifikan selain spasi tunggal di antara karakter non-spasi putih perlu dikutip (karena jika tidak, shell akan mengubah spasi putih menjadi, secara efektif, spasi tunggal, dan memangkas spasi kosong di depan atau di belakang).
Saat Anda mengetahui bahwa suatu variabel hanya dapat berisi nilai yang tidak berisi karakter meta shell, mengutip adalah opsional. Jadi, $?
yang tidak dikutip pada dasarnya baik-baik saja, karena variabel ini hanya dapat berisi satu angka. Namun, "$?"
juga benar, dan direkomendasikan untuk konsistensi dan kebenaran umum (meskipun ini adalah rekomendasi pribadi saya, bukan kebijakan yang diakui secara luas).
Nilai yang bukan variabel pada dasarnya mengikuti aturan yang sama, meskipun Anda juga dapat keluar dari karakter meta apa pun alih-alih mengutipnya. Sebagai contoh umum, URL dengan &
di dalamnya akan diuraikan oleh shell sebagai perintah latar belakang kecuali karakter meta diloloskan 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 kutipan atau pelolosan 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 berguna, yang saya suka sebut "pengutipan jungkat-jungkit". Jika Anda perlu menggabungkan tanda kutip tunggal dan ganda, Anda dapat menggunakannya berdekatan satu sama lain. Misalnya, string yang dikutip berikut
'$HOME '
"isn't"
' where `<3'
"' is."
dapat ditempelkan bersama secara berurutan, membentuk satu string panjang setelah tokenisasi dan penghapusan kutipan.
$ echo '$HOME '"isn't"' where `<3'"' is."
$HOME isn't where `<3' is.
Ini tidak terlalu mudah dibaca, tetapi ini adalah teknik yang umum dan karenanya baik untuk diketahui.
Selain itu, skrip biasanya tidak boleh menggunakan ls
untuk apa pun. Untuk memperluas karakter pengganti, cukup ... gunakan.
$ 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
(Loop benar-benar berlebihan dalam contoh terakhir; printf
secara khusus berfungsi dengan baik dengan banyak argumen. stat
juga. Namun mengulangi pencocokan karakter pengganti adalah masalah umum, dan sering kali dilakukan dengan tidak benar.)
Variabel yang berisi daftar token untuk diulangi atau karakter pengganti untuk diperluas lebih jarang terlihat, sehingga terkadang kami menyingkat menjadi "mengutip semuanya kecuali Anda tahu persis apa yang Anda lakukan".
Berikut adalah rumus tiga poin untuk kutipan secara umum:
Kutipan ganda
Dalam konteks di mana kami ingin menekan pemisahan kata dan globbing. Juga dalam konteks di mana kita ingin literal diperlakukan sebagai string, bukan regex.
Kutipan tunggal
Dalam string literal di mana kita ingin menekan interpolasi dan perlakuan khusus garis miring terbalik. Dengan kata lain, situasi di mana menggunakan tanda kutip ganda tidak pantas.
Tidak ada kutipan
Dalam konteks di mana kami benar-benar yakin bahwa tidak ada masalah pemisahan kata atau globbing atau kami ingin pemisahan kata dan globbing .
Contoh
Kutipan ganda
- string literal dengan spasi putih (
"StackOverflow rocks!"
,"Steve's Apple"
) - ekspansi variabel (
"$var"
,"${arr[@]}"
) - pergantian perintah (
"$(ls)"
,"`ls`"
) - gumpalan di mana jalur direktori atau bagian nama file menyertakan spasi (
"/my dir/"*
) - untuk melindungi tanda kutip tunggal (
"single'quote'delimited'string"
) - Ekspansi parameter bash (
"${filename##*/}"
)
Kutipan tunggal
- nama perintah dan argumen yang memiliki spasi di dalamnya
- string literal yang membutuhkan interpolasi untuk ditekan (
'Really costs $$!'
,'just a backslash followed by a t: \t'
) - untuk melindungi tanda kutip ganda (
'The "crux"'
) - regex literal yang membutuhkan interpolasi untuk ditekan
- gunakan kutipan shell untuk literal yang melibatkan karakter khusus (
$'\n\t'
) - gunakan kutipan shell di mana kita perlu melindungi beberapa tanda kutip tunggal dan ganda (
$'{"table": "users", "where": "first_name"=\'Steve\'}'
)
Tidak ada kutipan
- di sekitar variabel numerik standar (
$$
,$?
,$#
dll.) - dalam konteks aritmatika seperti
((count++))
,"${arr[idx]}"
,"${string:start:length}"
- di dalam
[[ ]]
ekspresi yang bebas dari pemisahan kata dan masalah globbing (ini masalah gaya dan pendapat bisa sangat bervariasi) - di mana kita ingin pemisahan kata (
for word in $words
) - di mana kita ingin globbing (
for txtfile in *.txt; do ...
) - di mana kita ingin
~
untuk ditafsirkan sebagai$HOME
(~/"some dir"
tapi bukan"~/some dir"
)
Lihat juga:
- Perbedaan antara tanda kutip tunggal dan ganda di Bash
- Apa variabel shell tanda dolar khusus?
- Kutipan dan melarikan diri - Wiki Bash Hacker
- Kapan kutipan ganda diperlukan?