Bash에서 숫자 비교


546

bash 터미널 용 스크립트 작성에 대해 배우기 시작했지만 비교가 올바르게 작동하는 방법을 알아낼 수 없습니다. 내가 사용하는 스크립트는 다음과 같습니다

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;

문제는 첫 번째 숫자의 숫자를 비교하는 것입니다. 즉 9는 10보다 크지 만 1은 09보다 큽니다.

진정한 비교를 위해 숫자를 유형으로 변환하는 방법은 무엇입니까?


1
기본 독서 : BashFAQ
Édouard Lopez

6
BTW에서 bash에서 세미콜론은 문장 종결자가 아닌 문장 구분 기호이며 줄 바꿈입니다. 따라서 한 줄에 하나의 진술 만 있으면 줄 ;끝이 불필요합니다. (당신이하지 않으면 안, 키 입력 만 낭비 어떤 해를 일을 즐길 세미콜론을 입력).
cdarke

6
소수에 0이 붙는 번호를 강제로 : 10#$number그래서 number=09; echo "$((10#$number))"뜻을 출력 9하는 동안 echo $((number))오류는 "기본에 대한 값이 너무 큰"생성합니다.
추후 공지가있을 때까지 일시 중지되었습니다.

4
대답은 모두 옳은 것이지만 틀린 것은 아닙니다 >. [명령 에서 연산자가하는 일은 두 문자열이 숫자로 정렬되는 순서가 아니라 정렬 해야하는 순서를 비교하는 것입니다. 에서 자세한 정보를 찾을 수 있습니다 man test.
user3035772

답변:


879

bash에서는 산술 컨텍스트 에서 확인을 수행해야합니다 .

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

지원하지 않는 POSIX 쉘의 경우 (()), 당신은 사용할 수 있습니다 -lt-gt.

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

당신은과 비교 연산자의 전체 목록을 얻을 수 있습니다 help test또는 man test.


7
@jordanm "$a" -gt "$b"이 말한 것처럼 정답입니다. 테스트 연산자의 좋은 목록은 다음과 같습니다. Test Constructs .
Jeffery Thomas

그것은 확실히 작동하지만 1과 09를 비교하지만 01과 09가 아닌 이상한 경우 "((: 09 : 너무 큰 값 (오류 토큰은"09 ")")를 얻지 만 기본적으로 해결되었습니다. ! 그래서 덕분에 내 문제
advert2013

8
@ advert2013에는 숫자 앞에 0을 붙여서는 안됩니다. 제로 접두사 번호는 떠들썩한 파티에 진수입니다
하기 Aleks 다니엘 Jakimenko-A.

8
test이 프로그램은있는 그대로 주의하십시오 [. 이에 help test대한 정보를 제공합니다. 내장 ( [[(() 기능을 찾으려면 help bash해당 부분을 사용 하고 탐색해야합니다.
RedX

1
산술 표현식은 훌륭하지만 피연산자는 표현식 으로 취급됩니다 .
x-yuri

179

평범하고 단순한

#!/bin/bash

a=2462620
b=2462620

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

Bash Scripting의 놀라운 세계에서 더 많은 숫자를 비교하고 싶다면 이 치트 시트를 확인하십시오 .

곧 정수는 다음과 만 비교할 수 있습니다.

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

따옴표의 주위에 - 그냥 다른 변화를 취소 한 "$a"하고 "$b"엄격하게 필요하지 않습니다하지만 그들은 좋은 방법이다. 중괄호는 여기서 유용한 것을 수행하지 않습니다.
Tom Fenech '

1
당신이 연결 한 위대한 치트 시트, 전에 그것을 찾지 못했습니다-이제 bash는 더 이상 마법과 예측할 수없는 것처럼 보이지 않습니다-감사합니다!
Ilja

따옴표는 "필수 [ $a -eq $b ]입니까, 아니면 괜찮습니까?
derHugo

@derHugo 따옴표는 선택 사항입니다. Gilles는 언제 사용 하는지
Daniel Andrei Mincă

주요 답변 +이 답변 = 완벽
Gabriel Staples

38

일부 사람들이 알지 못하는 좋은 점이 하나 있습니다.

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

이 코드는 가장 작은 숫자를 인쇄 a하고b


5
그건 사실이 아니야. bif 인 경우 에도 인쇄 됩니다 a == b.
konsolebox

88
@ konsolebox는 나입니까, 아니면 5와 5 중에서 가장 작은 숫자는 5입니까?
Aleks-Daniel Jakimenko-A.

4
당신의 진술은 모호합니다. 이와 같은 명령에도 적용 할 수 없습니다 :echo "The smaller number is $(( a < b ? a : b ))."
konsolebox

4
그가 말하는 a < b것은 여전히 ​​if a == b입니다. 나는 Bash의 조건 문의 모든 미치광이를 알지 못하지만 이것이 분명히 달라질 수있는 상황이 거의 있습니다.
bikemule

4
@bikemule 아니, 그는 그렇게 말하지 않습니다. 이면 false a == ba < b평가되어 인쇄 b됩니다.
mapeters

21

Bash에서는 (( ))더 많은 산술 연산을 사용 하는 것과 달리 조건부 연산으로 더 많이 처리 하므로이 작업을 선호합니다 .

[[ N -gt M ]]

내가 같은 복잡한 일을하지 않는 한

(( (N + 1) > M ))

그러나 모든 사람은 자신의 취향을 가지고 있습니다. 안타깝게도 일부 사람들은 비공식 표준을 강요합니다.

최신 정보:

실제로이 작업을 수행 할 수도 있습니다.

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

[[ ]]산술 이외의 다른 작업을 추가 할 수 있습니다.


3
이것은 그 암시하는 것 같다 [[ ]]산술 컨텍스트와 같은 힘을 (( ))N이있는 것처럼 처리됩니다 $N,하지만 난 그 올바른 생각하지 않습니다. 또는 의도가 아닌 경우 사용법 NM혼동됩니다.
Benjamin W.

@BenjaminW. 이것은 Chet의 확인이 필요하지만 -eq, -ne, -lt, -le, -gt 및 -ge는 "산술 테스트"(문서화)의 형태이며 피연산자가 다음과 같이 산술 표현식에 종속됨을 암시 할 수 있습니다. 음 ..
konsolebox

완전히 맞아하고,이에 다시와 주셔서 감사 매뉴얼이 명확하게 진술한다 : "함께 사용하면 [[명령 Arg1Arg2산술 표현식 [...]로 평가됩니다."
Benjamin W.

내가 가지고 NUMBER=0.0; while [[ "$NUMBER" -lt "1.0" ]]; do있고bash: [[: 0.0: syntax error: invalid arithmetic operator (error token is ".0")
Aaron Franke

@AaronFranke Bash 산술은 소수를 지원하지 않습니다.
konsolebox

6

이 코드는 또한 수레를 비교할 수 있습니다. awk를 사용하고 있지만 순수한 bash는 아닙니다. awk는 기본적으로 운영 체제와 함께 제공되는 표준 POSIX 명령이므로 문제가되지 않습니다.

$ 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 $?

더 짧게 사용하려면이 기능을 사용하십시오.

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
나는 많은 수의 일을하고 있는데 bash그것들을 올바르게 비교하지 못합니다 (시도 if (( 18446744073692774399 < 8589934592 )); then echo 'integer overflow'; fi). awk매력처럼 작동합니다 ( if awk "BEGIN {return_code=(18446744073692774399 > 8589934592) ? 0 : 1; exit} END {exit return_code}"; then echo 'no integer overflow'; fi).
jaume

3

수레가있는 경우 함수를 작성한 다음 예를 들어 사용할 수 있습니다

#!/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

부동 소수점 숫자를 사용하려면 대괄호 (예 : [[ $a -gt $b ]]또는 (( $a > $b )))로는 충분하지 않습니다. 구문 오류를보고합니다. 부동 수 또는 부동 수를 정수와 비교하려면을 사용할 수 있습니다 (( $(bc <<< "...") )).

예를 들어

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

if 문에 둘 이상의 비교를 포함 할 수 있습니다. 예를 들어

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

숫자 변수 (정수 여부)가 숫자 범위 내에 있는지 확인하려는 경우 유용합니다.


이것은 나를 위해 작동하지 않습니다. 내가 알 수있는 한, bc 명령은 종료 값을 반환하지 않고 비교가 참이면 "1"을 인쇄하고 그렇지 않으면 "0"을 인쇄합니다. 대신 이것을 써야합니다 :if [ "$(bc <<<"$a > $b") == "1" ]; then echo "a is greater than b; fi
Terje Mikal

@TerjeMikal 당신의 명령에 대해서 if [ $(bc <<<"$a > $b") == "1" ]; then echo "a is greater than b"; fi? (귀하의 명령이 잘못 작성되었다고 생각합니다.) 그렇다면 작동합니다. Bash Calculator (bc) 명령은 기본 계산기 명령입니다. 더 많은 사용 예제는 여기여기에 있습니다 . 내 예제 명령이 왜 작동하지 않는지 모르겠습니다.
LC-datascientist

2

버전 문자열을 비교할 수있는 일반 정수 값으로 변환하는 작은 함수를 사용 하여이 문제를 해결했습니다.

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

이것은 두 가지 중요한 가정을합니다.

  1. 입력은 " normal SemVer string "
  2. 각 부분은 0-999 사이입니다

예를 들어

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

npm명령이 최소 요구 사항을 충족하는지 테스트하는 예 ...

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'를 사용하면 버전 번호를 정렬 한 다음 수행 할 작업을 결정할 수 있습니다. 다음과 같이 비교 함수를 작성할 수 있습니다. function version_lt () {test "$ (printf '% s \ n'"$ @ "| sort -V | head -n 1)"== "$ 1"; } 다음과 같이 사용하십시오 : if version_lt $ v1 $ v2; 그때 ...
koem
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.