쉘 스크립트에서 프로그램 버전을 비교하는 방법은 무엇입니까?


14

gcc시스템에 최소 버전이 설치되어 있는지 여부를 확인하기 위해 버전 을 비교하고 싶다고 가정 하십시오.

gcc버전 을 확인하기 위해 다음을 실행했습니다.

gcc --version | head -n1 | cut -d" " -f4

출력은

4.8.5

그래서이 if값을 다른 값과 비교 하여 간단한 진술을 작성했습니다.

if [ "$(gcc --version | head -n1 | cut -d" " -f4)" -lt 5.0.0 ]; then
    echo "Less than 5.0.0"
else
    echo "Greater than 5.0.0"
fi

그러나 오류가 발생합니다.

[: integer expression expected: 4.8.5

나는 문자열을 사용하여 비교하고 -lt정수 가 필요 하다는 나의 실수를 이해했다 . 그렇다면 버전을 비교하는 다른 방법이 있습니까?


@ 123 아무 일도 일어나지 않습니다
Abhimanyu Saharan

1
버전 문자열을 비교하기위한 여러 가지 제안이 있는 스택 오버플로 질문 도 있습니다.
n.st

1
파이프를 사용하는 것보다 훨씬 간단합니다 :gcc -dumpversion
Victor Lamoine

답변:


22

나는 그것이 아름다운지 모르겠지만, 내가 알고있는 모든 버전 형식에서 작동합니다.

#!/bin/bash
currentver="$(gcc -dumpversion)"
requiredver="5.0.0"
 if [ "$(printf '%s\n' "$requiredver" "$currentver" | sort -V | head -n1)" = "$requiredver" ]; then 
        echo "Greater than or equal to 5.0.0"
 else
        echo "Less than 5.0.0"
 fi

( 참고 : 사용자 '와일드 카드'의 더 나은 버전 : https://unix.stackexchange.com/users/135943/wildcard , 추가 조건 제거)


3
처음에는 이것이 끔찍하다고 생각한 다음, 쉘 스크립팅의 아름다움이 이와 같은 도구를 남용한다는 것을 깨달았습니다. +1
Monica Cellio의 보이콧 SE

2
인쇄 문에 '%'기호가 있으면 중단됩니다. 로 교체 printf "$requiredver\n$currentver"하는 것이 printf '%s\n' "$requiredver" "$currentver"좋습니다.
phk

1
-Vsort(1)따라서이 솔루션은 GNU 확장 이므로 이식 할 수 없습니다.
stefanct

1
sort -n숫자 버전의 경우 거의 같은 방식으로 작동합니다.
Rockallite

1
@LucianoAndressMartini, 내 편집에 대한 당신의 생각을 참조하십시오.
와일드 카드

2

여기에 유닉스 커널 버전을 비교할 수있는 솔루션이 있습니다. 그리고 gcc와 같은 다른 사람들에게도 효과가 있습니다. 처음 2 개의 버전 번호 만 신경 쓰지만 다른 논리 계층을 추가 할 수 있습니다. 그것은 하나의 라이너이며 이해를 위해 여러 줄로 썼습니다.

check_linux_version() {
    version_good=$(uname -r | awk 'BEGIN{ FS="."}; 
    { if ($1 < 4) { print "N"; } 
      else if ($1 == 4) { 
          if ($2 < 4) { print "N"; } 
          else { print "Y"; } 
      } 
      else { print "Y"; }
    }')

    #if [ "$current" \< "$expected" ]; then
    if [ "$version_good" = "N" ]; then
        current=$(uname -r)
        echo current linux version too low
        echo current Linux: $current
        echo required 4.4 minimum
        return 1
    fi
}

이를 수정하여 gcc 버전 확인에 사용할 수 있습니다.


+1 다른 유닉스 계열과 호환됩니까? (내 솔루션은 없습니다)
루치아노 안드레스 마티니

1

우리는 GNU makefile에서 많은 버전을 검사했습니다. 우리는 makefile 기능을 통해 껍질을 벗겼습니다. 우리는 오래된 Binutils와 버그가있는 컴파일러를 감지하여 즉시 해결해야했습니다.

우리가 사용한 패턴은 다음과 같습니다.

#!/usr/bin/env bash

CC=$(command -v gcc)
GREP=$(command -v grep)

# Fixup CC and GREP as needed. It may be needed on AIX, BSDs, and Solaris
if [[ -f "/usr/gnu/bin/grep" ]]; then
    GREP="/usr/gnu/bin/grep"
elif [[ -f "/usr/linux/bin/grep" ]]; then
    GREP="/usr/linux/bin/grep"
elif [[ -f "/usr/xpg4/bin/grep" ]]; then
    GREP="/usr/xpg4/bin/grep"
fi

# Check compiler for GCC 4.8 or later
GCC48_OR_LATER=$("$CXX" -v 2>&1 | "$GREP" -i -c -E "gcc version (4\.[8-9]|[5-9]\.)")
if [[ "$GCC48_OR_LATER" -ne 0 ]];
then
   ...
fi

# Check assembler for GAS 2.19 or later
GAS219_OR_LATER=$("$CXX" -xc -c /dev/null -Wa,-v -o/dev/null 2>&1 | "$GREP" -c -E "GNU assembler version (2\.19|2\.[2-9]|[3-9])")
if [[ "$GAS219_OR_LATER" -ne 0 ]];
then
   ...
fi

좋은! 이것은 작동하고 확장하기 쉽고 매우 휴대하기 쉽습니다!
Brad Parks

1

더 짧은 버전 :

version_greater_equal()
{
    printf '%s\n%s\n' "$2" "$1" | sort -V -C
}

version_greater_equal "${gcc_version}" 8.2 || die "need 8.2 or above"

(1) 이것은 이미 주어진 답변의 작은 변형입니다. 아직 게시되지 않은 설명을 추가하여 가치를 추가 할 수 있습니다. (2)  printf '%s\n'충분하다. printf필요에 따라 형식 문자열을 반복합니다.
G-Man,

나는 일반적으로 기존 답변을 편집하는 것을 선호하지만 그중 절반을 삭제하는 것은 까다 롭습니다. 다른 사람들은 내가 그렇지 않은 곳에 가치를 볼 수 있습니다. 자세한 설명도 마찬가지입니다. 더 적은 것입니다.
MarcH

나는 그것이 printf형식 문자열 을 반복 한다는 것을 알고 있지만 이것에 대한 (부족한) 구문은 IMHO 모호합니다. 그래서 필요할 때만 사용합니다 = 인수 수가 크거나 가변적 인 경우.
MarcH

1
function version_compare () {
  function sub_ver () {
    local len=${#1}
    temp=${1%%"."*} && indexOf=`echo ${1%%"."*} | echo ${#temp}`
    echo -e "${1:0:indexOf}"
  }
  function cut_dot () {
    local offset=${#1}
    local length=${#2}
    echo -e "${2:((++offset)):length}"
  }
  if [ -z "$1" ] || [ -z "$2" ]; then
    echo "=" && exit 0
  fi
  local v1=`echo -e "${1}" | tr -d '[[:space:]]'`
  local v2=`echo -e "${2}" | tr -d '[[:space:]]'`
  local v1_sub=`sub_ver $v1`
  local v2_sub=`sub_ver $v2`
  if (( v1_sub > v2_sub )); then
    echo ">"
  elif (( v1_sub < v2_sub )); then
    echo "<"
  else
    version_compare `cut_dot $v1_sub $v1` `cut_dot $v2_sub $v2`
  fi
}

### Usage:

version_compare "1.2.3" "1.2.4"
# Output: <

크레딧은 @Shellman으로 갑니다

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.