if 문 및 연산자에서 소수점이 있는 숫자 사용

if 문 및 연산자에서 소수점이 있는 숫자 사용

조건과 연산자를 사용하여 Linux 운영 체제와 버전을 감지하고 결과에 따라 다른 명령을 실행하는 스크립트를 작성하려고 합니다.

운영 체제 감지

if [ -f /etc/os-release ]; then 
    . /etc/os-release 
    OS="$NAME" 
    OS_version="$VERSION_ID" 
elif [ -f /etc/debian_version ]; then 
    # Older Debian/Ubuntu/etc. 
    OS="Debian" 
    OS_version="$(cat /etc/debian_version)" 
fi

이 변수를 에코하면 반환됩니다.

$ echo $OS 
Debian GNU/Linux

$ echo $OS_version 
10

아래 예에서는 일치시키고 싶습니다.더반및 운영 체제 버전10. 하지만, 그$운영 체제변수에는 단어 이상의 내용이 포함됩니다.더반따라서 부분 일치를 수행하려면 일종의 와일드카드가 필요합니다.

명령 대체를 통해 작동하게 만드는 유일한 방법은 에코하는 것입니다.$운영 체제변수를 stdout으로 변환하고 grep 명령으로 파이프한 다음 와일드카드 검색을 수행합니다. 이것은 내가 생각해낸 if 문입니다.

if [ "$(echo "$OS" | grep 'Debian*')" -a "$OS_version" -ge 10 ]; then 
    echo "OS is Debian" 
    sleep 4 
else  
    echo "OS is other" 
    sleep 4 
fi

나는 이 스크립트를 다른 Unix 기반 운영 체제에서 사용할 것이기 때문에 이 스크립트를 최대한 광범위하게 호환되게 만들고 POSIX 표준을 준수하고 싶습니다.

Ubuntu 21.04에서 스크립트를 테스트하는 동안 Linux에서는 소수 자릿수가 포함될 때 어떤 숫자가 다른 숫자보다 큰지 파악하는 데 어려움을 겪는다는 사실을 발견했습니다. 아래에서는 두 개의 정수를 소수점 이하 두 자리로 내보내고 if 문을 사용하여 다른 숫자보다 크거나 같은지 확인하는 두 개의 쉘 스크립트를 만들었습니다.

20.10.sh

#!/bin/sh
export OS_version="20.10"

if [ "$OS_version" -ge 21.04 ]; then
    echo "Your OS is new enough"
    sleep 2
else
    echo "Your OS is too old!"
    sleep 2
fi

20.10.sh 출력

~$ ./20.10.sh 
YOUR OS VERSION IS >> 20.10 
./20.10.sh: 6: [: Illegal number: 20.10 
Your OS is too old!

23.45.sh

#!/bin/sh
export OS_version="23.45" 
if [ "$OS_version" -ge 21.04 ]; then 
    echo "Your OS is new enough" 
    sleep 2 
else 
    echo "Your OS is too old!" 
    sleep 2 
fi

23.45.sh 출력

~$ ./23.45.sh 
YOUR OS VERSION IS >> 23.45 
./23.45.sh: 6: [: Illegal number: 23.45 
Your OS is too old!

이것23.45.sh스크립트는 "귀하의 운영 체제가 충분히 새롭습니다."를 에코해야 하지만 에코하지 않고 잘못된 숫자에 대한 오류를 표시합니다.

소수점 이하 자릿수로 다른 숫자의 크기를 감지하는 방법이 있습니까?

답변1

표준 [명령은 숫자 비교 연산자로 십진 정수만 지원합니다. 일부 [구현(예: [내장 구현)은 ksh93부동 소수점 숫자와 확장을 지원하지만 이는 이식성이 없으며 어쨌든 부동 소수점 비교는 버전 비교와 동일하지 않습니다.

예를 들어 10.2부동 소수점 숫자는 보다 크지만 10.10버전으로 해석되면 그 반대가 됩니다.

우분투 버전은 날짜입니다. 20.04(2020년 4월)는 20.10(2010년 10월) 이전입니다. 이를 위해 어휘 비교를 사용할 수 있습니다(willreach awk10을 사용하여 수행할 수 있음).

1.2pre5-beta1.21.2while 보다 작은 것은 1.2a일반적으로 보다 큰 것으로 간주됩니다 1.2. 버전 명명 규칙을 모르면 버전을 비교하기 어려운 경우가 많습니다.

sortGNU 시스템에서는 GNU 의 알고리즘을 따를 수도 있습니다 --version-sort.

version_greater_than() {
  local before_sort="$1"$'\n'"$2"
  [ "$before_sort" != "$(printf %s "$before_sort" | sort --stable --version-sort)" ]
}

(ksh93/zsh/bash 구문) 또는 이에 sh상응하는 구문:

version_greater_than() {
  [ "$1
$2" != "$(printf '%s\n' "$1" "$2" | sort --stable --version-sort)" ]
}

그런 다음 다음을 수행할 수 있습니다.

if version_greater_than 10.10 10.4; then
  echo 10.10 greater than 10.4
fi

awkPOSIXly에서는 모든 숫자 시퀀스를 임의의 길이로 0으로 채우고 C 로케일에서 어휘 비교를 수행하는 접근 방식을 취할 수 있습니다 .

compare_versions() {
  LC_ALL=C awk -- '
    function pad(v,  ret) {
      while (match(v, /[0-9]+/)) {
        ret = ret substr(v, 1, RSTART - 1) \
              sprintf("%09d", substr(v, RSTART, RLENGTH))
        v = substr(v, RSTART + RLENGTH)
      }
      return ret v
    }
    BEGIN {exit !(pad(ARGV[1]) '"$2"' pad(ARGV[2]))}' "$1" "$3"
}

다음과 같이 사용됩니다:

if compare_versions 1.10 '>' 1.2; then
  echo '1.10 > 1.2'
fi

답변2

-lt고정 -ge소수점 또는 부동 소수점 비교 에는 또는 같은 연산자를 사용할 수 없습니다 . 이들은 엄격한 정수 수학 연산자입니다. bash(예) 정수가 아닌 수학을 수행하는 방법을 모릅니다. <버전 번호를 문자열로 비교하려면 eg 또는 를 사용해야 합니다 >=. 또한 eg 가 1.1"보다 큼" 에 유의해야 합니다 1.10. sort -v논리를 구축하여 이 문제를 해결할 수 있습니다 .

답변3

버전 번호가 부동 소수점(20.04.3과 같은 버전이 아님)인 경우 비교를 bc.

예를 들어 다음과 같이 변경합니다.

if [ "$OS_version" -ge 21.04 ]; then

이와 관련하여:

if [ $(echo "$OS_version >= 21.04" | bc) ]; then

관련 정보