Bash'deki sayıları karşılaştırma


546

Ben bash terminali için komut dosyası yazma hakkında bilgi edinmeye başladım, ancak karşılaştırmaları düzgün bir şekilde nasıl çalıştıracağımı öğrenemiyorum. Kullandığım komut dosyası:

echo "enter two numbers";
read a b;

echo "a=$a";
echo "b=$b";

if [ $a \> $b ];
then 
    echo "a is greater than b";
else
    echo "b is greater than a";
fi;

Sorun, ilk basamaktaki sayıyı karşılaştırmasıdır, yani 9, 10'dan büyük, ancak 1, 09'dan büyüktür.

Gerçek bir karşılaştırma yapmak için sayıları bir türe nasıl dönüştürebilirim?


1
Temel okuma: BashFAQ
Édouard Lopez

6
BTW, bash'ta bir noktalı virgül, yeni bir satır olan bir deyim sonlandırıcı değil, bir deyim ayırıcıdır. Dolayısıyla, bir satırda yalnızca bir ifadeniz varsa, satır ;sonundaki gereksizdir. (Eğer sürece değil, tuş vuruşlarını sadece bir atık zarar vermelerini zevk noktalı virgül yazarak).
cdarke

6
Baştaki sıfırlarla sayıları ondalık sayılara zorlamak için: 10#$numberbu durumda number=09; echo "$((10#$number))"çıktı 9verilirken echo $((number))"taban için çok büyük bir değer" hatası üretilir.
sonraki duyuruya kadar duraklatıldı.

4
Yanıtların hepsi size neyin doğru olduğunu, ancak neyin yanlış olduğunu >söylemez : operatörün [komutta yaptığı şey, iki dizenin sayı olarak sıralayacağı sıradan ziyade sıralaması gereken sırayı karşılaştırmaktır. İçinde daha fazla bilgi bulabilirsiniz man test.
user3035772

Yanıtlar:


879

Bash'da, çekinizi aritmetik bağlamda yapmalısınız :

if (( a > b )); then
    ...
fi

Desteklemeyen POSIX kabukları için (())kullanabileceğiniz -ltve -gt.

if [ "$a" -gt "$b" ]; then
    ...
fi

Sen ile karşılaştırma operatörleri tam bir listesini alabilirsiniz help testya man test.


7
@Jordanm tarafından söylendiği gibi "$a" -gt "$b"doğru cevaptır. İşte test operatörünün iyi bir listesi: Test Constructs .
Jeffery Thomas

Bu kesinlikle işe yarıyor ama hala alıyorum "((: 09: taban için çok büyük bir değer (hata belirteci" 09 ")" 1 ve 09'u karşılaştırırsam, ancak garip olan 01 ve 09'u karşılaştırırsam, ancak temelde çözüldü benim sorunum çok teşekkürler!
advert2013

8
@ advert2013 sayıların önüne sıfır eklememelisiniz. sıfır ön ekli sayılar
bashta

8
Bu testbir program olduğu gibi sakının [. Yani help testbu konuda bilgi verir. Yerleşiklerin ( [[ve (() ne yaptığını bulmak help bashiçin bu bölümü kullanmalı ve o bölüme gitmelisiniz.
RedX

1
Aritmetik ifadeler harika, ancak işlenenler ifadeler olarak kabul edilir .
x-yuri

179

Sade ve basit

#!/bin/bash

a=2462620
b=2462620

if [ "$a" -eq "$b" ];then
  echo "They're equal";
fi

Bash Scripting'in harika dünyasında daha fazla sayı karşılaştırması istiyorsanız bu hile sayfasına göz atabilirsiniz .

Kısacası, tamsayılar yalnızca aşağıdakilerle karşılaştırılabilir:

-eq # equal
-ne # not equal
-lt # less than
-le # less than or equal
-gt # greater than
-ge # greater than or equal

Diğer değişikliğinizi çözdüm - çift tırnak işaretleri "$a"ve "$b"kesinlikle gerekli değil ama iyi bir uygulama. Kıvırcık parantez burada yararlı bir şey yapmaz.
Tom Fenech

1
Bağladığınız harika bir hile sayfası, daha önce bulamadınız - şimdi bash artık çok sihirli ve öngörülemez görünüyor - teşekkürler!
Ilja

alıntılar "zorunlu mu yoksa sadece [ $a -eq $b ]iyi mi?
derHugo

@derHugo alıntıları isteğe bağlıdır. Gilles, bunları ne zaman kullanacağınız konusunda daha iyi bir açıklamaya sahip. Unix.stackexchange.com/a/68748/50394
Daniel Andrei Mincă

Ana cevap + bu cevap = mükemmel
Gabriel Staples

38

Bazı insanların bilmediği güzel bir şey de var:

echo $(( a < b ? a : b ))

Bu kod, en küçük sayıyı aveb


5
Bu doğru değil. Ayrıca baskı olur beğer a == b.
konsolebox

88
@konsolebox sadece ben mi, yoksa 5 ve 5'in en küçük sayısı 5 mi?
Aleks-Daniel Jakimenko-A.

4
İfadeniz belirsiz. Bunun gibi bir komutta bile uygulama yapılmaz:echo "The smaller number is $(( a < b ? a : b ))."
konsolebox

4
Söylediği a < bşey hala doğru a == b. Bash'ın koşullarının tüm kaprislerini bilmiyorum, ancak bunun kesinlikle bir fark yaratacağı durumlar var.
bikemule

4
@bikemule Hayır, bunu söylemiyor. Eğer a == b, o zaman a < bfalse olarak değerlendirilen bu yazdıracak neden olan b.
mapeters

21

Bash'te bunu (( ))daha çok aritmetik olandan farklı olarak koşullu bir işlem olarak ele aldığı için yapmayı tercih ederim .

[[ N -gt M ]]

Tabii gibi karmaşık şeyler yapmadıkça

(( (N + 1) > M ))

Ancak herkesin kendi tercihleri ​​var. Üzücü olan şey, bazı insanların gayri resmi standartlarını dayatmasıdır.

Güncelleme:

Aslında bunu da yapabilirsiniz:

[[ 'N + 1' -gt M ]]

Bu, [[ ]]aritmetik işlerin yanı sıra yapabileceğiniz başka bir şey eklemenizi sağlar .


3
Bu , sanki sanki sanki sanki sanki [[ ]]aritmetik bir bağlamı zorladığını ima ediyor , ama bunun doğru olduğunu düşünmüyorum. Ya da, eğer niyet bu değilse, kullanımı ve kafa karıştırıcı. (( ))N$NNM
Benjamin W.

Bu, Chet'ten onay gerektirir, ancak -eq, -ne, -lt, -le, -gt ve -ge, işlenenlerin aritmetik ifadelere tabi olduğunu ima edebilecek "aritmetik testlerin" (belgelenmiş) formlarıdır. iyi ..
konsolebox

Tamamen haklısınız gibi, bu kadar geri geldiğiniz için teşekkür manuel açıkça belirtmektedir: "kullanıldığında [[komuta, Arg1ve Arg2aritmetik ifadeler [...] olarak değerlendirilir".
Benjamin W.

Ben var NUMBER=0.0; while [[ "$NUMBER" -lt "1.0" ]]; dove diyorbash: [[: 0.0: syntax error: invalid arithmetic operator (error token is ".0")
Aaron Franke

@AaronFranke Bash aritmetiği ondalık basamakları desteklemez.
konsolebox

6

Bu kod ayrıca şamandıraları karşılaştırabilir. Awk kullanıyor (saf bash değil), ancak awk muhtemelen işletim sisteminizle varsayılan olarak gönderilen standart bir POSIX komutu olduğundan bu bir sorun olmamalıdır.

$ awk 'BEGIN {return_code=(-1.2345 == -1.2345) ? 0 : 1; exit} END {exit return_code}'
$ echo $?
0
$ awk 'BEGIN {return_code=(-1.2345 >= -1.2345) ? 0 : 1; exit} END {exit return_code}'
$ echo $?
0
$ awk 'BEGIN {return_code=(-1.2345 < -1.2345) ? 0 : 1; exit} END {exit return_code}'
$ echo $?
1
$ awk 'BEGIN {return_code=(-1.2345 < 2) ? 0 : 1; exit} END {exit return_code}'
$ echo $?
0
$ awk 'BEGIN {return_code=(-1.2345 > 2) ? 0 : 1; exit} END {exit return_code}'
$ echo $?

Kullanım süresini kısaltmak için bu işlevi kullanın:

compare_nums()
{
   # Function to compare two numbers (float or integers) by using awk.
   # The function will not print anything, but it will return 0 (if the comparison is true) or 1
   # (if the comparison is false) exit codes, so it can be used directly in shell one liners.
   #############
   ### Usage ###
   ### Note that you have to enclose the comparison operator in quotes.
   #############
   # compare_nums 1 ">" 2 # returns false
   # compare_nums 1.23 "<=" 2 # returns true
   # compare_nums -1.238 "<=" -2 # returns false
   #############################################
   num1=$1
   op=$2
   num2=$3
   E_BADARGS=65

   # Make sure that the provided numbers are actually numbers.
   if ! [[ $num1 =~ ^-?[0-9]+([.][0-9]+)?$ ]]; then >&2 echo "$num1 is not a number"; return $E_BADARGS; fi
   if ! [[ $num2 =~ ^-?[0-9]+([.][0-9]+)?$ ]]; then >&2 echo "$num2 is not a number"; return $E_BADARGS; fi

   # If you want to print the exit code as well (instead of only returning it), uncomment
   # the awk line below and comment the uncommented one which is two lines below.
   #awk 'BEGIN {print return_code=('$num1' '$op' '$num2') ? 0 : 1; exit} END {exit return_code}'
   awk 'BEGIN {return_code=('$num1' '$op' '$num2') ? 0 : 1; exit} END {exit return_code}'
   return_code=$?
   return $return_code
}

$ compare_nums -1.2345 ">=" -1.2345 && echo true || echo false
true
$ compare_nums -1.2345 ">=" 23 && echo true || echo false
false

1
Ben büyük sayılarla çalışıyorum ve bashonları düzgün karşılaştırmak için başarısız (deneyin if (( 18446744073692774399 < 8589934592 )); then echo 'integer overflow'; fi). awkbir cazibe gibi çalışır ( if awk "BEGIN {return_code=(18446744073692774399 > 8589934592) ? 0 : 1; exit} END {exit return_code}"; then echo 'no integer overflow'; fi).
jaume

3

Şamandıralarınız varsa bir işlev yazıp kullanabilirsiniz.

#!/bin/bash

function float_gt() {
    perl -e "{if($1>$2){print 1} else {print 0}}"
}

x=3.14
y=5.20
if [ $(float_gt $x $y) == 1 ] ; then
    echo "do stuff with x"
else
    echo "do stuff with y"
fi

3

Kayan sayıları da kullanmak istiyorsanız , parantez öğeleri (örn., [[ $a -gt $b ]]Veya (( $a > $b ))) yeterli değildir; sözdizimi hatası verir. Kayan sayıları veya kayan sayıları tamsayı ile karşılaştırmak istiyorsanız, kullanabilirsiniz (( $(bc <<< "...") )).

Örneğin,

a=2.00
b=1

if (( $(bc <<<"$a > $b") )); then 
    echo "a is greater than b"
else
    echo "a is not greater than b"
fi

İf ifadesine birden fazla karşılaştırma ekleyebilirsiniz. Örneğin,

a=2.
b=1
c=1.0000

if (( $(bc <<<"$b == $c && $b < $a") )); then 
    echo "b is equal to c but less than a"
else
    echo "b is either not equal to c and/or not less than a"
fi

Sayısal bir değişkenin (tamsayı ya da değil) sayısal bir aralık içinde olup olmadığını kontrol etmek istiyorsanız bu yararlıdır.


Bu benim için işe yaramıyor. Anlayabildiğim kadarıyla, bc komutu bir çıkış değeri döndürmez, bunun yerine karşılaştırma doğru ise "1" yazar (aksi takdirde "0"). Bunun yerine şunu yazmak zorundayım:if [ "$(bc <<<"$a > $b") == "1" ]; then echo "a is greater than b; fi
Terje Mikal

@TerjeMikal Komutunuz için mi demek istediniz if [ $(bc <<<"$a > $b") == "1" ]; then echo "a is greater than b"; fi? (Bence emriniz yanlış yazılmıştı.) Öyleyse, bu da işe yarıyor. Bash Calculator (bc) komutu temel bir hesap makinesi komutudur. Burada ve burada bulunan bazı kullanım örnekleri . Örnek komutumun sizin için neden işe yaramadığını bilmiyorum.
LC-veri bilimcisi

2

Bu sürüm dizeleri karşılaştırılabilir düz tamsayı değerlere dönüştürmek için küçük bir işlev kullanarak çözüldü:

function versionToInt() {
  local IFS=.
  parts=($1)
  let val=1000000*parts[0]+1000*parts[1]+parts[2]
  echo $val
}

Bu iki önemli varsayımda bulunur:

  1. Giriş " normal bir SemVer dizesidir "
  2. Her bölüm 0-999 arasında

Örneğin

versionToInt 12.34.56  # --> 12034056
versionToInt 1.2.3     # -->  1002003

npmKomutun minimum gereksinimi karşılayıp karşılamadığına ilişkin örnek test ...

NPM_ACTUAL=$(versionToInt $(npm --version))  # Capture npm version
NPM_REQUIRED=$(versionToInt 4.3.0)           # Desired version
if [ $NPM_ACTUAL \< $NPM_REQUIRED ]; then
  echo "Please update to npm@latest"
  exit 1
fi

'sort -V' ile sürüm numaralarını sıralayabilir ve sonra ne yapacağınıza karar verebilirsiniz. Bunun gibi bir karşılaştırma işlevi yazabilirsiniz: function version_lt () {test "$ (printf '% s \ n'" $ @ "| sort -V | head -n 1)" == "$ 1"; } ve şu şekilde kullanın: if version_lt $ v1 $ v2; sonra ...
koem
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.