Bisakah seseorang memberi tahu saya apakah saya harus membungkus tanda kutip di sekitar variabel dalam skrip shell?
Sebagai contoh, apakah yang berikut ini benar:
xdg-open $URL
[ $? -eq 2 ]
atau
xdg-open "$URL"
[ "$?" -eq "2" ]
Dan jika demikian, mengapa?
Jawaban:
Aturan umum: kutip jika itu bisa kosong atau mengandung spasi (atau spasi kosong apa pun) atau karakter khusus (wildcard). Tidak mengutip string dengan spasi sering menyebabkan shell memecah satu argumen menjadi banyak.
$?
tidak perlu penawaran karena ini adalah nilai numerik. Apakah$URL
kebutuhan itu 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.
sumber
IFS=0
, makaecho $?
bisa sangat mengejutkan.cp $source1 $source2 $dest
, tetapi jika karena alasan yangdest
tidak terduga tidak ditetapkan, argumen ketiga menghilang, dan itu akan secara diam-diam menyalinsource1
alih-source2
alih memberi Anda kesalahan yang sesuai untuk tujuan kosong (seperti yang akan terjadi jika Anda telah mengutip setiap argumen).quote it if...
memiliki proses berpikir mundur - kutipan bukanlah sesuatu yang Anda tambahkan saat Anda perlu, itu sesuatu yang Anda hapus saat Anda perlu. Selalu bungkus string dan skrip dalam tanda kutip tunggal kecuali jika Anda perlu menggunakan tanda kutip ganda (misalnya untuk membiarkan variabel berkembang) atau perlu menggunakan tanda kutip tidak ada (misalnya untuk melakukan globbing dan ekspansi nama file).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.
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.)
Tidak ada kutipan yang cocok ketika Anda secara khusus meminta shell untuk melakukan pemisahan token dan / atau ekspansi wildcard.
Pemisahan Token;
Sebaliknya:
(Loop hanya berjalan sekali, di atas string tunggal, yang dikutip.)
(Loop hanya berjalan sekali, di atas string tunggal yang dikutip.)
Ekspansi wildcard:
Sebaliknya:
(Tidak ada file bernama harfiah
file*.txt
.)(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:(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.
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
dapat disisipkan bersama kembali ke belakang, membentuk string panjang tunggal setelah tokenization dan penghapusan kutipan.
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.(Pengulangan benar-benar berlebihan dalam contoh terakhir;
printf
secara khusus berfungsi dengan baik dengan beberapa argumenstat
. 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".
sumber
Berikut adalah rumus tiga poin untuk kutipan secara umum:
Kutipan ganda
Dalam konteks di mana kami ingin menekan pemisahan kata dan penggumpalan. Juga dalam konteks di mana kita ingin literal diperlakukan sebagai string, bukan regex.
Kutipan tunggal
Dalam string literal di mana kami ingin menekan interpolasi dan perlakuan khusus backslash. Dengan kata lain, situasi di mana menggunakan tanda kutip ganda tidak pantas.
Tidak ada kutipan
Dalam konteks di mana kita benar-benar yakin bahwa tidak ada masalah pemisahan kata atau penggumpalan atau kita memang ingin pemisahan kata dan penggumpalan .
Contohnya
Kutipan ganda
"StackOverflow rocks!"
,"Steve's Apple"
)"$var"
,"${arr[@]}"
)"$(ls)"
,"`ls`"
)"/my dir/"*
)"single'quote'delimited'string"
)"${filename##*/}"
)Kutipan tunggal
'Really costs $$!'
,'just a backslash followed by a t: \t'
)'The "crux"'
)$'\n\t'
)$'{"table": "users", "where": "first_name"=\'Steve\'}'
)Tidak ada kutipan
$$
,$?
,$#
dll)((count++))
,"${arr[idx]}"
,"${string:start:length}"
[[ ]]
ekspresi di dalam yang bebas dari masalah pemisahan kata dan penggumpalan (ini masalah gaya dan pendapat bisa sangat bervariasi)for word in $words
)for txtfile in *.txt; do ...
)~
ditafsirkan sebagai$HOME
(~/"some dir"
tetapi tidak"~/some dir"
)Lihat juga:
sumber
"ls" "/"
Frasa "semua konteks string" harus dikualifikasi lebih hati-hati.[[ ]]
, mengutip tidak masalah di sisi kanan=
/==
dan=~
: itu membuat perbedaan antara menafsirkan string sebagai pola / regex atau secara harfiah.$'...'
) harus memiliki bagian mereka sendiri."ls" "/"
daripada yang lebih umumls /
, dan saya menganggap itu sebagai cacat utama dalam pedoman.case
:)Saya biasanya menggunakan dikutip seperti
"$var"
untuk aman, kecuali saya yakin itu$var
tidak mengandung ruang.Saya menggunakan
$var
cara sederhana untuk bergabung dengan baris:sumber
Untuk menggunakan variabel dalam skrip shell gunakan "" variabel yang dikutip seperti yang dikutip berarti bahwa variabel tersebut mungkin berisi spasi atau karakter khusus yang tidak akan mempengaruhi eksekusi skrip shell Anda. Jika Anda yakin tidak memiliki spasi atau karakter khusus dalam nama variabel Anda, maka Anda dapat menggunakannya tanpa "".
Contoh:
echo "$ nama url" - (Dapat digunakan setiap saat)
echo "$ url name" - (Tidak dapat digunakan pada situasi seperti itu jadi berhati-hatilah sebelum menggunakannya)
sumber