Mengapa menggunakan kutip ganda dalam tes [[]]?

23

Katakanlah kita memiliki 2 bilangan bulat dalam skrip bash:

value1=5
value2=3

Lalu mengapa kita perlu menggunakan tanda kutip ganda untuk ujian? Sebagai contoh:

if [[ "$value1" -eq "$value2" ]]

Mengapa tidak menggunakan saja yang berikut ini?

if [[ $value1 -eq $value2 ]]

Bagi saya, tanda kutip ganda tidak masuk akal.

Meerkat
sumber
5
Mengutip di shell tidak ada hubungannya dengan string (seperti dalam tipe data). Ini benar-benar tentang mencegah shell dari melakukan pemisahan kata (dan jenis ekspansi lainnya.)
filbranden
13
Sementara, seperti yang ditunjukkan terdon, tidak perlu terlalu mengutip variabel dalam konstruksi spesifik ini (dan, tentu saja, dengan nilai satu kata di mana saja), saya ingin memberikan saran untuk selalu mengutip vars Anda. Apakah Anda benar-benar tahu dalam konteks mana Anda dapat membiarkan variabel tidak dikutip? Alasan untuk mengutip sama sekali, bahkan jika itu tidak perlu dengan 5dan 3, adalah rawatan. Nilai dapat berubah nanti, dan kesalahan yang dihasilkan mungkin tidak jelas.
Peter - Pasang kembali Monica
2
@sudodus Saya pikir itu tidak benar [[ ]], hanya untuk [ ].
Benjamin W.
1
Anda benar, @BenjaminW. Pemisahan kata bukan satu-satunya alasan mengapa ini adalah ide yang baik untuk menggunakan tanda kutip ganda untuk variabel. Ada juga kasus ketika sebuah variabel kosong. Itu akan membuat pernyataan dalam [] gagal (misalnya [2 -eq] dengan kesalahan, tetapi [[]] tidak rentan (seperti halnya dengan pemisahan kata)
sudodus
2
@marcelm, Bash, ksh dan Zsh memiliki variabel integer, dan di dalamnya [[ ]]mereka juga memaksa operan -equntuk integer.
ilkkachu

Jawaban:

7

Pemisahan kata.

Contoh ini sangat tidak mungkin, tetapi mungkin , jadi jika Anda ingin membuat kode secara defensif, tutupi trek Anda dengan tanda kutip:

$ set -x
$ value1=5
+ value1=5
$ value2=3
+ value2=3
$ [ $value1 -eq $value2 ]
+ '[' 5 -eq 3 ']'

OK, semua baik sejauh ini. Mari kita lemparkan kunci pas ke roda gigi:

$ IFS=456
+ IFS=456
$ [ $value1 -eq $value2 ]
+ '[' '' -eq 3 ']'
bash: [: : integer expression expected

Ups.

$ [ "$value1" -eq "$value2" ]
+ '[' 5 -eq 3 ']'

Ahh.

glenn jackman
sumber
2
Tapi OP menggunakan tanda kurung ganda, jadi tidak ada pemisahan kata.
user000001
5
Ya, ini tidak terlalu relevan dengan [[ ]]konstruk bash .
terdon
1
Eh? [ $value1 -eq $value2 ]dengan yang kosong value1akan '[' -eq 3 ']'tanpa ''di sisi kiri.
Charles Duffy
Saya terkejut juga, tetapi ada buktinya.
glenn jackman
1
Jawaban ini tidak secara langsung berhubungan dengan pertanyaan. Saya terkejut itu diterima. Pengaturan sebagai wiki komunitas.
glenn jackman
35

Anda sebenarnya tidak memerlukan tanda kutip di sini. Ini adalah salah satu dari sedikit kasus di mana aman untuk menggunakan variabel yang tidak dikutip. Anda dapat mengkonfirmasi ini dengan set -x:

$ var1=""
$ var2="3"
$ set -x
$ if [[ $var1 -eq $var2 ]]; then echo "match!"; else echo "no match!"; fi
+ [[ '' -eq 3 ]]
+ echo 'no match!'
no match!
$ if [[ "$var1" -eq "$var2" ]]; then echo "match!"; else echo "no match!"; fi
+ [[ '' -eq 3 ]]
+ echo 'no match!'
no match!

Seperti yang Anda lihat di atas, versi tes yang dikutip dan tidak dikutip diselesaikan dengan hal yang sama persis oleh bash. Hal yang sama harus berlaku untuk zshdan, saya pikir, shell lain yang mendukung [[ ]]operator.

Perhatikan bahwa tidak demikian halnya dengan yang lebih portabel [ ]:

$ if [ $var1 -eq $var2 ]; then echo "match!"; else echo "no match!"; fi
+ '[' -eq 3 ']'
sh: [: -eq: unary operator expected
+ echo 'no match!'
no match!

The [ ]membangun, tidak seperti [[ ]]satu, memang membutuhkan mengutip.


Beberapa tautan bermanfaat untuk mempelajari lebih lanjut tentang kapan dan mengapa mengutip diperlukan:

terdon
sumber
Dalam hal ini dengan variabel integer akan lebih baik untuk mendeklarasikannya seperti itu. declare -i var1=adalah 0ketika dievaluasi.
Freddy
4
Perhatikan bahwa -eqini adalah perbandingan aritmatika , sehingga Anda bahkan dapat meninggalkan bagian $luar (dalam [[ .. ]]), dan menulis [[ a -eq b ]]. Dengan perbandingan string, Anda perlu $, tentu saja, jadi[[ $a = $b ]]
ilkkachu
2
@ user000001 poin bagus. Meskipun, tentu saja, sangat mungkin Anda ingin yang diperluas. Sebagai contoh, saya akan berharap ini menjadi pertandingan: var1="afoob"; var2="a*b"; [[ $var1 = $var2 ]] && echo match. Jika Anda ingin menggunakan karakter glob tanpa aktingnya sebagai glob dalam konteks globbing (seperti [[ ]]) maka Anda perlu mengutip, ya.
terdon
3
@ilkkachu, itu mengejutkan saya. Saya pikir bahwa variabel "telanjang" hanya akan dipertimbangkan dalam array subscript atau ((...))atau $((...). Tampaknya bekerja, tetapi (orang tua yang pemarah, memungkinkan) saya tidak suka itu.
glenn jackman
1
@ glennjackman, yah, maaf untuk menjadi orang yang memberitahu Anda itu, tapi ya, operan ke -eqdan teman-teman di dalam [[ ]]konteks aritmatika juga. :) (Terkait: Perintah ekspansi variabel otomatis di dalam bash [[]] )
ilkkachu
17

Meskipun tanda kutip ganda tidak diperlukan, alasan untuk menggunakannya adalah:

  • Praktek / kebiasaan yang baik: Dalam hal ini mereka tidak perlu, tetapi secara umum tanda kutip ganda adalah untuk menghindari pemisahan kata yang tidak diinginkan.
  • Karena value1dan value2variabel, dan Anda mungkin tidak tahu apa isinya. Kalau tidak, Anda mungkin juga bertanya, "Mengapa repot-repot dengan variabel daripada memeriksa if [[ 5 -eq 3 ]]? Atau mengambil lebih jauh, mengapa repot-repot dengan ifsama sekali ketika Anda sudah tahu bahwa 5 tidak sama dengan 3? Sering kali lebih baik bersikap defensif. (Memang benar pemisahan kata tidak akan terjadi [[, tetapi kasus di mana pemisahan kata tidak terjadi jarang terjadi. Sekali lagi, lihat poin pertama.)
jamesdlin
sumber
1

Tidak terkait langsung dengan pertanyaan Anda, tetapi saya gunakan

if (($ value1 == $ value2)); kemudian

ketika saya membandingkan angka tetapi di sana Anda juga tidak perlu menggunakan tanda kutip.

Framp
sumber
2
if (( value1 == value2 )); then. Dalam konteks aritmatika, Anda bahkan tidak memerlukannya $. Namun, pertanyaan ini tampaknya berfokus pada variabel yang digunakan dalam [[ ... ]]tes.
Kusalananda
1
Aku tahu. Tapi saya terus terang tidak menggunakan fitur ini karena saya ingin agar nama variabel saya konsisten dan karenanya menggunakan $ sebagai awalan sepanjang waktu.
framp
1

Anda benar sekali!

Mengutip dalam kurung kotak ganda tidak masuk akal sama sekali, setidaknya dalam kasus ini.

Tapi karena saya menggunakan tanda kutip ganda setiap hari - terutama untuk ekspresi kurung siku tunggal, menyampaikan argumen ke fungsi dan skrip, serta kadang-kadang penugasan variabel (yang sama sekali tidak berguna untuk delcarations sederhana) - Saya kira beberapa orang, setidaknya saya lakukan, menulis tanda kutip ganda di sekitar ekspansi variabel secara naluriah .

Kutipan ganda dapat memberi Anda rasa jeli. Ini seperti pulang ke rumah di mana tanda kutip ganda berada. - D. Kummer

Manfaat melakukan double quote secara konsekuen dan komprehensif - tetapi hanya jika masuk akal - adalah bahwa rekan kerja yang baru mengenal bash dapat belajar bagaimana menulis skrip yang lebih stabil . Ini juga menekankan fakta bahwa seni pemrosesan data dengan bash lebih tentang memisahkan aliran data (termasuk variabel) dengan pemisah lapangan dan menyalurkannya melalui filter . Segera setelah Anda memisahkan data dari aliran, pegang bersama dengan tanda kutip ganda!

Manfaat lain bisa berupa keterbacaan skrip bash yang lebih baik dengan string yang dikutip ganda dalam editor penyorot kode .

Dominik Kummer
sumber