シェルスクリプトでプログラムのバージョンを比較する方法は?


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

比較に文字列を使用していて、-ltrequiresに整数が必要であるという私の間違いを理解しました。では、バージョンを比較する他の方法はありますか?


@ 123何も起こらない
Abhimanyu Saharan

1
バージョン文字列を比較するためのさまざまな提案がたくさんあるStack Overflowの質問もあります。
n.st、2016年

1
パイプを使用するよりもはるかに簡単:gcc -dumpversion
Victor Lamoine

回答:


21

それが美しいかどうかはわかりませんが、私が知っているすべてのバージョンフォーマットで機能しています。

#!/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
モニカチェリオのボイコットSE 2016年

2
これは、印刷ステートメントに '%'記号があると壊れます。より良い置き換えるprintf "$requiredver\n$currentver"printf '%s\n' "$requiredver" "$currentver"
phk 2016年

1
-VGNUの拡張であるsort(1)ため、このソリューションは、据え置き型です。
stefanct 2017

1
sort -n数字バージョンの場合とほとんど同じように機能します。
Rockallite

1
@LucianoAndressMartini、私の編集についてどう思うか見てください。
ワイルドカード

2

ここでは、Unixカーネルのバージョンを比較するためのソリューションを示します。そして、それは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それは他のUnixライクと互換性がありますか?(私の解決策はそうではありません)
Luciano Andress Martini

1

以前は、GNU 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

いいね!これは機能し、拡張が非常に簡単で、非常にポータブルです!
ブラッドパークス

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フォーマット文字列が繰り返されていることはわかっていますが、この構文の(欠けている!)構文は、私見ではあいまいです。したがって、私はこれが必要な場合にのみ使用します=引数の数が多いか可変である場合。
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.