Bir değişkeni dizge olarak veya int olarak karşılaştırırken büyük bir fark var mı?


22

Merak dışında, bir bash değişkeni karşılaştırması yaparken (değeri an integer) bir intya da a olarak bildirilen önceden tanımlanmış bir değere karşı test etmek mümkündür string.

Örnek komut dosyası :

#!/bin/bash
f1()
{
        [ "$1" == "1" ] && echo "$FUNCNAME: \"1\" compared as string"
}

f2()
{
        [[ "$1" -eq 1 ]] && echo "$FUNCNAME: \"1\" compared as int"
}

f1 $1
f2 $1

Çıktı :

$  ./param.sh 1
f1: "1" compared as string
f2: "1" compared as int

ve

$  ./param.sh blah
$

Her iki fonksiyon da aynı şekilde davranır ve bu yüzden bir tamsayı değişkenini kontrol ederken tercih edilen bir yol olup olmadığını merak ediyorum. Ben kontrol etmek için gider intkarşı intdaha sıkı olduğu gibi ama ile yapıyor herhangi kura destek vardır acaba string?

Bu durumda, f2()karşılaştırma konusunda da daha katıdır, yani ondalık bir değer iletmek onu bozacaktır, oysa f1()sorun çıkarmayacaktır.


Bash'in bir Tamsayı veri türüne sahip olmadığını unutmayın. Temel olarak bir String'i bir tamsayı olarak değerlendirmek için Bash'e ipucu verebilirsiniz.
helpermethod

Yanıtlar:


18

Evet, çok fazla fark var. Örneğin, =tam dize eşitliği için denetler, ancak -eqeşitliği denetlemeden önce her iki ifadeyi de aritmetik olarak değerlendirir:

$ [ " 1 " -eq 1 ] && echo equal || echo not
equal
$ [ " 1 " = 1 ] && echo equal || echo not
not

$ [ +1 -eq 1 ] && echo equal || echo not
equal
$ [ +1 = 1 ] && echo equal || echo not
not

$ [ "0+1" -eq 1 ] && echo equal || echo not
equal
$ [ "0+1" = 1 ] && echo equal || echo not
not

Ayrıca, boş dize sayısal olarak sıfıra eşit olur:

$ [ "" -eq 0 ] && echo equal || echo not
equal
$ [ "" = 0 ] && echo equal || echo not
not

Eğer karşılaştırma operatörlerini getirdiklerinde Ve farklılıkların bambaşka sınıf görünüyor - dikkate <vs -ltÖrneğin:

$ [[ 2 -lt 10 ]] && echo less || echo not
less
$ [[ 2 < 10 ]] && echo less || echo not
not

Bunun nedeni, "2" dizesinin "10" dizesinden sonra alfabetik olarak (1'den önce 1 geldiğinden beri), ancak "2" sayısının sayısal olarak "10" sayısından daha az olmasıdır.


2
(( ... ))Sayısal işlemler için de olduğunu unutma . (( " 1 " == 1 )) && echo yes || echo nosonuçlarıyes
Patrick

7

Tamsayı ile dize karşılaştırması, şunlardan daha büyük veya daha küçük karşılaştırırken en belirgin hale gelir:

#!/bin/bash

eleven=11
nine=9

[[ $nine < $eleven ]] && echo string   # fail

[[ "$nine" -lt "$eleven" ]] && echo integer # pass

İlki başarısız oluyor çünkü 9, sözlükten sonra sıralandığında 11'den sonra geliyor.

Kota kullanmanın dizeleri veya sayıları karşılaştırıp karşılaştırmadığınızı belirlemediğini unutmayın, operatör yapar. Yukarıdaki alıntıları ekleyebilir veya kaldırabilirsiniz, herhangi bir fark yaratmaz. Bash, çift parantez içinde tanımsız değişkenleri yakalar, bu nedenle tırnak işaretleri gerekli değildir. Sayısal testler için tekli parantezli tırnak kullanmak, o zamandan beri sizi kurtarmaz:

[ "" -lt 11 ]

yine de bir hatadır ("tamsayı ifadesi gerekli"). Tırnaklar, tekli parantez içindeki string karşılaştırmalarıyla etkili bir korumadır:

[ "" \< 11 ]

Çift parantez içindeki not , ""olacaktır -eq 0ama olmayacak == 0.


1
Kısacası, değişkenleri çift parantez içinde alıntılamak kesinlikle gerekli değildir: yerleşik [[değişkenlerin nerede olduğunu hatırlayacak kadar akıllıdır ve boş değişkenler tarafından kandırılmayacaktır. Tek ayraçlar ( [) bu özelliğe sahip değildir ve tırnak gerektirir.
glenn jackman

@glennjackman Bunu farketmemiştim. [[ -lt 11 ]]bir hatadır, ama nothing=; [[ $nothing -lt 11 ]]değildir. Son paragrafı biraz elden geçirdim.
goldilocks

2

Söylenenlere ek olarak.
Kabuk yazarken hızlı bir şekilde hesaplamaya ihtiyaç duymanız çok nadir olmasına rağmen, eşitlik karşılaştırması sayılarla daha hızlıdır.

$ b=234
$ time for ((a=1;a<1000000;a++)); do [[ $b = "234" ]]; done

real    0m13.008s
user    0m12.677s
sys 0m0.312s

$ time for ((a=1;a<1000000;a++)); do [[ $b -eq 234 ]]; done

real    0m10.266s
user    0m9.657s
sys 0m0.572s

Farklı şeyler yaptıklarını göz önünde bulundurarak, performansın alakasız olduğunu söyleyebilirim. İstediğinizi yapanı kullanmanız gerekir.
godlygeek

@godlygeek Bir değişkenin eşitlik karşılaştırması her iki şekilde de yapılabilir. "-eq" daha hızlı.
Emmanuel,

Farklı eşitlik tanımları için test yaparlar. Eğer soruya cevap vermek istiyorsanız, sadece kullanabilirsiniz "bu değişken tutma kesin dize 123 mu" =kullanarak beri, -eq"+123" için de eşleşir. "Bu değişken, aritmetik bir ifade olarak değerlendirildiğinde, 123 ile aynı değeri karşılaştırır" bilmek istiyorsanız, yalnızca kullanabilirsiniz -eq. Bir programcının hangi eşitlik tanımının kullanıldığını umursamadığını görebildiğim tek zaman, değişken içeriğinin zamanın belirli bir düzeniyle sınırlı olduğunu bildiği zamandır.
godlygeek

@godlygeek ilginç, soru, sayıların eşitliğini dizelermiş gibi karşılaştırmakla ilgiliydi, önceden belli bir kalıpla sınırlandırılmış değişkenler durumuna uyuyor mu?
Emmanuel,

Example ( b=234) yönteminiz bu forma uyuyor - siz kendiniz atadığınız için +234 veya "234" veya "233 + 1" olmadığını biliyorsunuz, yani onu bir string ve sayı olarak karşılaştırdığınızı biliyorsunuz. Fakat OP'nin senaryosu, komut satırı argümanı olarak girdi aldığı için, o kısıtlamaya sahip değil - onu ./param.sh 0+1ya da olarak adlandırmayı düşünün./param.sh " 1"
godlygeek
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.