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

小数点を削除する必要があり、実際のバージョン番号比較を提供できないため、これは実際には悪いことです。もう1つの問題は、いくつかの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最後のスペースの前の内容をすべて削除して終了します(したがって数字のみを印刷します)。

フィールド区切り記号で設定されたフラグ-Fawk.

最初の数字(ドットの前)が2より大きい場合または最初の数字が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つの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

バージョン文字列を整数に変換しないでください。文字列を比較します。

これはあなたのユースケースに比べて少し過剰ですが、ここでは文字列シェル関数のより一般的なバージョンがあります。それはのサブセットに従いますDebian バージョン比較ルール:

  • バージョンはブロックごとに比較されます。各ブロックは、数字のみで構成されるか、数字を含まない最大文字シーケンスで構成されます。
  • 数値以外のシーケンスはアルファベット順に比較されます。
  • 一連の数値は、小数値に基づいて比較されます。特に先行するゼロは無関係です。

最後のビットは1.01同じとして扱われます1.1。これは以下で支払い1.11.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
)

関連情報