Bisakah seseorang tolong jelaskan perbedaan antara -eq
dan ==
dalam skrip bash?
Apakah ada perbedaan antara yang berikut ini?
[ $a -eq $b ]
dan [ $a == $b ]
Apakah hanya itu yang ==
hanya digunakan ketika variabel berisi angka?
Ini sebaliknya: =
dan ==
untuk perbandingan string, -eq
adalah untuk numerik. -eq
adalah dalam keluarga yang sama seperti -lt
, -le
, -gt
, -ge
, dan -ne
, jika yang membantu Anda ingat yang mana.
==
omong-omong, omong-omong. Lebih baik menggunakan POSIX =
. Dalam bash keduanya sama, dan di sh polos =
adalah satu-satunya yang dijamin untuk bekerja.
$ a=foo
$ [ "$a" = foo ]; echo "$?" # POSIX sh
0
$ [ "$a" == foo ]; echo "$?" # bash specific
0
$ [ "$a" -eq foo ]; echo "$?" # wrong
-bash: [: foo: integer expression expected
2
(Catatan: Kutip ekspansi variabel itu! Jangan tinggalkan tanda kutip ganda di atas.)
Jika Anda menulis #!/bin/bash
skrip maka saya sarankan menggunakan [[
sebagai gantinya . Bentuk ganda memiliki lebih banyak fitur, sintaksis yang lebih alami, dan lebih sedikit Gotcha yang akan membuat Anda tersandung. Kutipan ganda tidak lagi diperlukan $a
, misalnya:
$ [[ $a == foo ]]; echo "$?" # bash specific
0
Lihat juga:
[[
secara keseluruhan adalah ksh-isme era 1980-an yang diadopsi oleh bash (dan banyak kerang lainnya). Itulah intinya - jika Anda memiliki[[
semuanya , maka Anda dapat dengan aman mengasumsikan bahwa semua ekstensi ksh diimplementasikan di sekitarnya (fnmatch()
pencocokan pola-gaya, ERE ekspresi reguler dengan=~
, dan ya, penindasan string-splitting dan penggumpalan sistem file) akan menjadi tersedia. Karena[[
sintaksinya adalah non-POSIX secara keseluruhan, tidak ada kerugian portabilitas tambahan dengan mengasumsikan bahwa fitur yang dilahirkannya akan tersedia.[[ $var = $pattern ]]
, jika Anda ingin apa yang seharusnya dapat diartikan sebagai pola fnmatch untuk bukan diartikan sebagai string literal. Stringfoo
tidak memiliki interpretasi non-literal, membuat meninggalkan kutipan sepenuhnya aman; itu hanya jika OP ingin mencocokkan, katakanlah,foo*
(dengan tanda bintang sebagai literal, tidak berarti apa pun yang dapat muncul setelah stringfoo
) yang mengutip atau melarikan diri akan diperlukan.[[
tanda kutip di dalam menjadi bashism (menunjukkan bahwa itu adalah satu-satunya alasan Anda tidak memberikan jawaban +1).[ ... ]
dan dobel tanda sama dengan==
. : - /Itu tergantung pada Uji Konstruksi di sekitar operator. Pilihan Anda adalah tanda kurung ganda, kawat gigi ganda, kawat gigi tunggal, atau tes
Jika Anda menggunakan ((...)) , Anda menguji ekuitas aritmatika dengan
==
seperti pada C:(Catatan:
0
berartitrue
dalam arti Unix dan bukan nol adalah tes gagal)Menggunakan
-eq
bagian dalam tanda kurung ganda adalah kesalahan sintaksis.Jika Anda menggunakan [...] (atau penjepit tunggal) atau [[...]] (atau penjepit ganda), atau
test
Anda dapat menggunakan salah satu dari -eq, -ne, -lt, -le, -gt, atau -ge sebagai perbandingan aritmatika .Bagian
==
dalam kawat gigi tunggal atau ganda (atautest
perintah) adalah salah satu operator perbandingan string :Sebagai operator string,
=
sama dengan==
dan perhatikan spasi putih di sekitar=
atau==
yang diperlukan.Meskipun Anda dapat melakukan
[[ 1 == 1 ]]
atau[[ $(( 1+1 )) == 2 ]]
sedang menguji kesetaraan string - bukan kesetaraan aritmatika.Jadi
-eq
menghasilkan hasil yang mungkin diharapkan bahwa nilai integer1+1
sama dengan2
meskipun RH adalah string dan memiliki ruang tambahan:Sementara perbandingan string yang sama mengambil ruang tambahan dan karenanya perbandingan string gagal:
Dan perbandingan string yang salah dapat menghasilkan jawaban yang salah sepenuhnya. '10' secara leksikografis kurang dari '2', sehingga perbandingan string mengembalikan
true
atau0
. Begitu banyak yang digigit oleh bug ini:vs tes yang benar untuk 10 secara aritmetika kurang dari 2:
Dalam komentar, ada pertanyaan tentang alasan teknis menggunakan integer
-eq
pada string mengembalikan True untuk string yang tidak sama:Alasannya adalah bahwa Bash tidak diketik . The
-eq
menyebabkan string ditafsirkan sebagai bilangan bulat jika mungkin termasuk konversi dasar:Dan
0
jika Bash berpikir itu hanya string:Jadi
[[ "yes" -eq "no" ]]
setara dengan[[ 0 -eq 0 ]]
Catatan terakhir: Banyak ekstensi spesifik Bash untuk Konstruk Uji tidak POSIX dan karenanya akan gagal di shell lain. Kerang lain umumnya tidak mendukung
[[...]]
dan((...))
atau==
.sumber
[[ "yes" -eq "no" ]]
mengembalikan True. Bagaimana bash memaksa string ini ke nilai integer yang dapat dibandingkan? ;-)[[ "yes" -eq "no" ]]
sama dengan[[ "yes" -eq 0 ]]
atau[[ "yes" -eq "any_noninteger_string" ]]
- Semua Benar. The-eq
pasukan bilangan bulat perbandingan. Ini"yes"
ditafsirkan sebagai bilangan bulat0
; perbandingannya Benar jika bilangan bulat lainnya baik0
atau hasil string0
.==
dalam sampel kode dan hanya menyebutkan (portabel, standar) di=
bawahnya.==
adalah alias spesifik-bash untuk=
dan melakukan perbandingan string (leksikal) alih-alih perbandingan numerik.eq
menjadi perbandingan angka tentu saja.Akhirnya, saya biasanya lebih suka menggunakan formulir
if [ "$a" == "$b" ]
sumber
==
sini adalah bentuk yang buruk, karena hanya=
ditentukan oleh POSIX.==
maka letakkan di antara[[
dan]]
. (Dan pastikan bahwa baris pertama skrip Anda ditentukan untuk digunakan/bin/bash
.)Guys: Beberapa jawaban menunjukkan contoh berbahaya. Contoh OP
[ $a == $b ]
secara khusus menggunakan substitusi variabel yang tidak dikutip (per Oktober '17 sunting). Untuk[...]
itu aman untuk kesetaraan string.Tetapi jika Anda akan menghitung alternatif seperti
[[...]]
, Anda harus memberi tahu juga bahwa sisi kanan harus dikutip. Jika tidak dikutip, itu adalah pencocokan pola! (Dari halaman bash man: "Bagian mana pun dari pola dapat dikutip untuk memaksa agar dicocokkan sebagai string.").Di sini, di bash, dua pernyataan yang menghasilkan "ya" adalah pencocokan pola, tiga lainnya adalah persamaan string:
sumber
[ "$lht" = "$rht" ]
dengan kutipan agar dapat diandalkan bahkan untuk kesetaraan. Jika Anda memiliki file yang dibuattouch 'Afoo -o AB'
,[ $lft = $rht ]
akan mengembalikan true, meskipun nama file itu sama sekali tidak identikAB
.