Apa perbedaan antara tanda sama dengan tunggal dan ganda (=) dalam perbandingan shell?

28

Baca itu untuk membandingkan string di dalam ifkita perlu menggunakan tanda kurung ganda. Beberapa buku mengatakan bahwa perbandingan dapat dilakukan oleh =. Tapi itu bekerja dengan baik ==juga.

#!/bin/bash
a="hello"
b="world"
if [[ $a == $b ]];then
    echo "equal"
fi

Apakah ada perbedaan antara =dan ==dalam perbandingan?

user3539
sumber
4
Apakah ada pertanyaan di sini? Jika demikian, saya tidak melihatnya. =adalah untuk [. ==adalah untuk [[.
Chris Down
@ ChrisDown Itu sama sekali tidak benar.
xdavidliu
@xdavidliu Peduli untuk menguraikan? Ini tentu adalah benar menurut POSIX, yang tidak memiliki pemahaman ==, yang mengapa Anda harus menggunakan =(kesetaraan) dengan [, dan ==(pencocokan pola, dengan semantik yang mengutip-sadar) dengan [[. Lihat help testvs help [[.
Chris Down
@ ChrisDown mungkin saya salah paham apa yang dimaksud dengan "adalah untuk". Jika "adalah untuk" berarti "hanya bekerja dengan", maka komentar tersebut tidak benar, karena [ foo == foo ] && echo footentu saja dicetak foo, yang menunjukkan bahwa ==bekerja dengan [. Namun, jika dengan "adalah untuk" maksud Anda "dimaksudkan untuk digunakan dengan", maka saya memiliki keberatan yang lebih kecil.
xdavidliu
@xdavidliu "adalah untuk" dalam kasus spesifik yang Anda sebutkan berarti "didefinisikan oleh POSIX". Hanya karena bash menerimanya sebagai kenyamanan, tidak berarti itu direkomendasikan - jika Anda menghindari portabilitas, gunakan saja [[yang memiliki pemahaman yang jauh lebih bernuansa tentang tokenisasi, pemisahan kata, dll ...
Chris Down

Jawaban:

28

[[ $a == $b ]]bukan perbandingan, itu pencocokan pola. Anda membutuhkan [[ $a == "$b" ]]perbandingan kesetaraan byte-ke-byte. =sama dengan ==shell yang mendukung [[...]](diperkenalkan oleh ksh).

[[...]]bukan shsintaks standar . The [ perintah standar, dan standar perbandingan Operator ada =(meskipun beberapa [implementasi juga mengakui ==).

Sama seperti dalam argumen apa pun untuk perintah apa pun, variabel harus dikutip, jadi:

[ "$a" = "$b" ]

Secara standar sh, pencocokan pola dilakukan dengan case:

case $a in
  ($b) ...
esac

Untuk kelengkapannya, operator serupa kesetaraan lainnya yang mungkin Anda jumpai dalam skrip shell:

  • [ "$a" -eq "$b" ]: standar [ operator untuk membandingkan angka integer desimal. Beberapa [implementasi memungkinkan kosong di sekitar angka, beberapa memungkinkan ekspresi aritmatika sewenang-wenang, tetapi itu tidak portabel. Mudah dibawa, seseorang dapat menggunakannya [ "$((a))" -eq "$((b))" ]untuk itu. Lihat juga [ "$((a == b))" -ne 0 ]yang akan menjadi setara standar (kecuali POSIXly, perilaku hanya ditentukan jika $adan $bmengandung konstanta integer) dari:
  • ((a == b)), dari ksh dan juga ditemukan di zsh dan bash, mengembalikan true jika evaluasi ekspresi aritmatika yang disimpan dalam $amenghasilkan angka yang sama dengan $b. Biasanya, itu digunakan untuk membandingkan angka. Perhatikan bahwa ada variasi di antara shell tentang bagaimana ekspresi aritmatika dievaluasi dan angka apa yang didukung (misalnya bash dan beberapa implementasi / versi ksh tidak mendukung floating point atau memperlakukan angka dengan angka nol di depan sebagai oktal).

  • expr "$a" = "$b"melakukan perbandingan angka jika kedua operan dikenali sebagai angka integer desimal (beberapa mengizinkan kekosongan di sekitar angka), dan sebaliknya memeriksa apakah dua operator string memiliki urutan pengurutan yang sama. Itu juga akan gagal untuk nilai $aatau$b yang exprseperti operator (, substr...

  • awk 'BEGIN{exit !(ARGV[1] == ARGV[2])}' "$a" "$b": jika $adan $bdikenali sebagai angka (setidaknya bilangan bulat desimal dan angka floating point seperti 1.2, -1.5e-4, blank trailing blank diabaikan, beberapa juga mengenali heksadesimal, oktal atau apa pun yang dikenali oleh strtod()), maka perbandingan numerik dilakukan. Jika tidak, tergantung pada implementasinya, itu adalah perbandingan string byte-ke-byte, atau seperti untukexpr sebuah strcoll()perbandingan, yaitu apakah $adan $bsemacam sama.

Lihat juga:

Stéphane Chazelas
sumber
13

Ini setara dengan bash:

[[ $x == "$y" ]]
[[ $x = "$y" ]]
[ "$x" == "$y" ]
[ "$x" = "$y" ]

Dua variabel $ x pertama tidak perlu dikutip. Bash melakukan pemisahan kata dan perluasan pathname di dalam [tetapi tidak di dalam [[:

$ x='a b'
$ [ -s $x ]
-bash: [: a: binary operator expected
$ [[ -s $x ]]
$ ls
$ [ a = * ]
-bash: [: a: unary operator expected
$ [[ a = * ]]
$ 

[[ $x = "$y" ]]adalah perbandingan string tetapi [[ $x = $y ]]ekspresi pencocokan pola:

$ y='a*'; [[ aa = "$y" ]]; echo $?
1
$ y='a*'; [[ aa = $y ]]; echo $?
0

-eq hanya dimaksudkan untuk digunakan dengan bilangan bulat:

$ [[ x.x -eq x.x ]]
-bash: [[: x.x: syntax error: invalid arithmetic operator (error token is ".x")
$ x=9; [[ "x" -eq 9 ]]; echo $?
0

Lihat juga BashFAQ / 031: Apa perbedaan antara tes, [dan [[? .

Lri
sumber