Operator Kesetaraan Bash (==, -eq)


136

Bisakah seseorang tolong jelaskan perbedaan antara -eqdan ==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?

Jawaban:


187

Ini sebaliknya: =dan ==untuk perbandingan string, -eqadalah untuk numerik. -eqadalah 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/bashskrip 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:


1
@DJCrashdummy, [[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.
Charles Duffy

1
@DJCrashdummy, ... link Anda menunjukkan poin dengan benar bahwa tanda kutip kadang-kadang diperlukan di sisi kanan dari [[ $var = $pattern ]], jika Anda ingin apa yang seharusnya dapat diartikan sebagai pola fnmatch untuk bukan diartikan sebagai string literal. String footidak 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 string foo) yang mengutip atau melarikan diri akan diperlukan.
Charles Duffy

@CharlesDuffy sayangnya saya tidak tahu apa yang Anda maksudkan, karena komentar saya tampaknya dihapus dan saya tidak ingat karena sudah cukup lama. :-(
DJCrashdummy

@DJCrashdummy, ... ya, saya berasumsi Anda akan mencabutnya sendiri. Pada dasarnya, itu adalah keberatan tentang ekspansi [[tanda kutip di dalam menjadi bashism (menunjukkan bahwa itu adalah satu-satunya alasan Anda tidak memberikan jawaban +1).
Charles Duffy

@CharlesDuffy tidak, itu bukan satu-satunya alasan: selain fakta bahwa saya tidak suka bash-isme, ksh-isme dll untuk tugas-tugas sederhana (itu hanya menyebabkan masalah dan membingungkan pemula), saya tidak mengerti mengapa mencampur satu kurung kurawal [ ... ]dan dobel tanda sama dengan ==. : - /
DJCrashdummy

27

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:

$ (( 1==1 )); echo $?
0
$ (( 1==2 )); echo $?
1

(Catatan: 0berarti truedalam arti Unix dan bukan nol adalah tes gagal)

Menggunakan -eqbagian dalam tanda kurung ganda adalah kesalahan sintaksis.

Jika Anda menggunakan [...] (atau penjepit tunggal) atau [[...]] (atau penjepit ganda), atau testAnda dapat menggunakan salah satu dari -eq, -ne, -lt, -le, -gt, atau -ge sebagai perbandingan aritmatika .

$ [ 1 -eq 1 ]; echo $?
0
$ [ 1 -eq 2 ]; echo $?
1
$ test 1 -eq 1; echo $?
0

Bagian ==dalam kawat gigi tunggal atau ganda (atau testperintah) adalah salah satu operator perbandingan string :

$ [[ "abc" == "abc" ]]; echo $?
0
$ [[ "abc" == "ABC" ]]; echo $?
1

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 -eqmenghasilkan hasil yang mungkin diharapkan bahwa nilai integer 1+1sama dengan 2meskipun RH adalah string dan memiliki ruang tambahan:

$ [[ $(( 1+1 )) -eq  "2 " ]]; echo $?
0

Sementara perbandingan string yang sama mengambil ruang tambahan dan karenanya perbandingan string gagal:

$ [[ $(( 1+1 )) ==  "2 " ]]; echo $?
1

Dan perbandingan string yang salah dapat menghasilkan jawaban yang salah sepenuhnya. '10' secara leksikografis kurang dari '2', sehingga perbandingan string mengembalikan trueatau 0. Begitu banyak yang digigit oleh bug ini:

$ [[ 10 < 2 ]]; echo $?
0

vs tes yang benar untuk 10 secara aritmetika kurang dari 2:

$ [[ 10 -lt 2 ]]; echo $?
1

Dalam komentar, ada pertanyaan tentang alasan teknis menggunakan integer -eqpada string mengembalikan True untuk string yang tidak sama:

$ [[ "yes" -eq "no" ]]; echo $?
0

Alasannya adalah bahwa Bash tidak diketik . The -eqmenyebabkan string ditafsirkan sebagai bilangan bulat jika mungkin termasuk konversi dasar:

$ [[ "0x10" -eq 16 ]]; echo $?
0
$ [[ "010" -eq 8 ]]; echo $?
0
$ [[ "100" -eq 100 ]]; echo $?
0

Dan 0jika Bash berpikir itu hanya string:

$ [[ "yes" -eq 0 ]]; echo $?
0
$ [[ "yes" -eq 1 ]]; echo $?
1

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== .


Saya ingin tahu tentang alasan teknis untuk [[ "yes" -eq "no" ]]mengembalikan True. Bagaimana bash memaksa string ini ke nilai integer yang dapat dibandingkan? ;-)
odony

4
Variabel Bash tidak diketik sehingga [[ "yes" -eq "no" ]]sama dengan [[ "yes" -eq 0 ]] atau [[ "yes" -eq "any_noninteger_string" ]]- Semua Benar. The -eqpasukan bilangan bulat perbandingan. Ini "yes"ditafsirkan sebagai bilangan bulat 0; perbandingannya Benar jika bilangan bulat lainnya baik 0atau hasil string 0.
dawg

Boo, desisnya kembali: menunjukkan (tidak dapat dipindahkan) ==dalam sampel kode dan hanya menyebutkan (portabel, standar) di =bawahnya.
Charles Duffy

24

==adalah alias spesifik-bash untuk =dan melakukan perbandingan string (leksikal) alih-alih perbandingan numerik. eqmenjadi perbandingan angka tentu saja.

Akhirnya, saya biasanya lebih suka menggunakan formulir if [ "$a" == "$b" ]


15
Menggunakan di ==sini adalah bentuk yang buruk, karena hanya =ditentukan oleh POSIX.
Charles Duffy

9
Jika Anda benar-benar bersikeras untuk menggunakannya ==maka letakkan di antara [[dan ]]. (Dan pastikan bahwa baris pertama skrip Anda ditentukan untuk digunakan /bin/bash.)
holgero

18

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:

$ rht="A*"
$ lft="AB"
$ [ $lft = $rht ] && echo yes
$ [ $lft == $rht ] && echo yes
$ [[ $lft = $rht ]] && echo yes
yes
$ [[ $lft == $rht ]] && echo yes
yes
$ [[ $lft == "$rht" ]] && echo yes
$

2
Perlu [ "$lht" = "$rht" ] dengan kutipan agar dapat diandalkan bahkan untuk kesetaraan. Jika Anda memiliki file yang dibuat touch 'Afoo -o AB', [ $lft = $rht ]akan mengembalikan true, meskipun nama file itu sama sekali tidak identik AB.
Charles Duffy
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.