Bash: 문자열(버전 번호)을 정수로 변환

Bash: 문자열(버전 번호)을 정수로 변환

glibc 버전을 구해 if 문에서 사용하여 glibc가 2.15 미만인지 확인하고 싶습니다.

그러나 문제는 ldd --version을 사용할 때 문자열로 출력된다는 것입니다. 비교를 위해 정수로 변환해야 합니다.

나는 이것을하곤했다

if [ "$(ldd --version | sed -n '1 p' | tr -cd '[:digit:]' | tail -c 3)" -lt 215 ]; then

소수점을 제거해야 하고 실제 버전 번호 비교를 제공할 수 없기 때문에 이는 실제로 좋지 않습니다. 또 다른 문제는 일부 glibc 버전에 소수점이 여러 개 있다는 것입니다(여기 참조).https://en.wikipedia.org/wiki/GNU_C_Library#Version_history) 이는 기존 비교가 엉망이 될 것임을 의미합니다.

따라서 이를 수행하려면 glibc 버전 전체를 정수로 변환하고 소수점이 여러 개인 경우에도 버전 번호를 정확하게 비교할 수 있어야 합니다.

어떤 아이디어가 있나요? 감사해요

답변1

ldd --version | sed 's/.* //;q' | awk -F. '{ if ($1 > 2 || ($1 == 2 && $2 >= 15)) { exit 0 } else {exit 1} }'

설명하다:

sed명령은 출력의 첫 번째 줄을 가져와서 ldd --version마지막 공백 앞의 모든 내용을 제거하고 종료합니다(따라서 숫자만 인쇄합니다).

필드 구분 기호로 설정된 플래그입니다 -F.awk.

첫 번째 숫자(점 앞)가 2보다 큰 경우또는첫 번째 숫자가 2이고 두 번째 숫자가 15 이상이면 awk종료 상태는 "true"가 됩니다. 그렇지 않으면 가짜입니다.

다음과 같은 스크립트에서 사용할 수 있습니다 bash.

if ldd --version | sed 's/.* //;q' | awk -F. '{ if ($1 > 2 || ($1 == 2 && $2 >= 15)) { exit 0 } else {exit 1} }' ; then
  echo "Version is 2.15 or later"
else
  echo "Version is too old."
fi

답변2

sort버전 번호는 이를 활용하여 다음과 같이 작성할 수 있습니다.

if [ $(printf '%s\n2.15\n' $(ldd --version | sed -n '1s/.* //p') | sort -V | head -n 1) != 2.15 ]; then
    # ...
fi

printf '%s\n2.15\n' $(ldd --version | sed -n '1s/.* //p')ldd버전 번호를 인쇄하고 두 개의 2.15개별 라인에서 sort -V오름차순으로 정렬 하고 head -n 1첫 번째 라인을 인쇄합니다. 외부 명령 대체는 출력으로 대체되고 출력은 으로 대체됩니다 2.15. 실행 본문이 실행됩니다.2.15if

내 컴퓨터의 출력 예 ldd 2.21:

% [ $(printf '%s\n2.15\n' $(ldd --version | sed -n '1s/.* //p') | sort -V | head -n 1) != 2.15 ] && printf 'Version %s is lower than 2.15\n' $(ldd --version | sed -n '1s/.* //p') || printf 'Version %s is equal or higher than 2.15\n' $(ldd --version | sed -n '1s/.* //p')
Version 2.21 is equal or higher than 2.15

버전 순서를 처리하는 이 메소드의 복잡성을 보여주기 위해 일부 하드코딩된 값이 포함된 출력 예:

% glibc_version=2.15
% [ $(printf '%s\n2.15\n' $glibc_version | sort -V | head -n 1) != 2.15 ] && printf 'Version %s is lower than 2.15\n' $glibc_version || printf 'Version %s is equal or higher than 2.15\n' $glibc_version
Version 2.15 is equal or higher than 2.15
% glibc_version=2.16  
% [ $(printf '%s\n2.15\n' $glibc_version | sort -V | head -n 1) != 2.15 ] && printf 'Version %s is lower than 2.15\n' $glibc_version || printf 'Version %s is equal or higher than 2.15\n' $glibc_version
Version 2.16 is equal or higher than 2.15
% glibc_version=2.15.1
[ $(printf '%s\n2.15\n' $glibc_version | sort -V | head -n 1) != 2.15 ] && printf 'Version %s is lower than 2.15\n' $glibc_version || printf 'Version %s is equal or higher than 2.15\n' $glibc_version
Version 2.15.1 is equal or higher than 2.15
% glibc_version=2.14
% [ $(printf '%s\n2.15\n' $glibc_version | sort -V | head -n 1) != 2.15 ] && printf 'Version %s is lower than 2.15\n' $glibc_version || printf 'Version %s is equal or higher than 2.15\n' $glibc_version
Version 2.14 is lower than 2.15

답변3

버전 문자열을 정수로 변환하지 마세요. 문자열을 비교합니다.

이는 귀하의 사용 사례에 비해 약간 과잉이지만 여기에는 문자열 셸 함수의 보다 일반적인 버전이 있습니다. 그것은의 하위 집합을 따릅니다데비안 버전 비교 규칙:

  • 버전은 블록별로 비교됩니다. 각 블록은 숫자로만 구성되거나 숫자가 포함되지 않은 최대 문자 시퀀스로 구성됩니다.
  • 숫자가 아닌 시퀀스는 사전순으로 비교됩니다.
  • 일련의 숫자는 소수 값을 기준으로 비교됩니다. 특히 앞에 오는 0은 관련이 없습니다.

마지막 비트는 1.01같음으로 처리됩니다 1.1. 이것은 아래에서 지불 1.1하고 1.9고려해야 할 가격입니다 1.10.

이 코드에는 dash, bash, ksh 또는 zsh가 필요합니다. 다른 셸(예: BusyBox sh)과 함께 사용하려면 by 호출을 로 바꾸세요.[ "STRING1" \> "STRING2" ]expr "aSTRING1" \> "aSTRING2"

version_ge () (
  version1="$1" version2="$2"
  while true; do
    prefix1="${version1%%[0-9]*}" prefix2="${version2%%[0-9]*}"
    if [ "$prefix1" \> "$prefix2" ]; then return 0; fi
    if [ "$prefix2" \> "$prefix1" ]; then return 1; fi
    version1="${version1#"$prefix1"}" version2="${version2#"$prefix2"}"
    prefix1="${version1%%[!0-9]*}" prefix2="${version2%%[!0-9]*}"
    version1="${version1#"$prefix1"}" version2="${version2#"$prefix2"}"
    case "$prefix2" in
      0*[!0]*) prefix2="${prefix2##"${prefix2%%[!0]*}"}";;
      *[!0]*) :;;
      *) return 0;;
    esac
    case "$prefix1" in
      0*[!0]*) prefix1="${prefix1##"${prefix1%%[!0]*}"}";;
      *[!0]*) :;;
      *) return 1;;
    esac
    if [ "${#prefix1}" -gt "${#prefix2}" ]; then return 0; fi
    if [ "${#prefix1}" -lt "${#prefix2}" ]; then return 1; fi
    if [ "$prefix1" \> "$prefix2" ]; then return 0; fi
    if [ "$prefix2" \> "$prefix1" ]; then return 1; fi
  done
)

관련 정보