Bashのバージョン番号が特定の番号以上であるかどうかをテストする必要があります。たとえば、私は持っています:
$ bash --version
GNU bash, version 4.3.48(1)-release (x86_64-pc-linux-gnu)
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
連想配列を使用するには、bashのバージョン番号が4以上でなければなりません。
私のbashスクリプトでは、可能な限り最もエレガント/効率的/読みやすい方法でワンライナーテストを行いたいが、他のアプローチも受け入れられます。
試してください:
$ [ "${BASH_VERSINFO:-0}" -ge 4 ] && echo "bash supports associative arrays"
bash supports associative arrays
BASH_VERSINFO
は、bashのこのインスタンスのバージョン情報を保持するメンバーを持つ読み取り専用の配列変数です。これはbash 2.0で導入されたため、おそらく遭遇するすべてのbashバージョンでサポートされています。ただし、注意するために、この変数が設定されていない以前のバージョンのbashには0
のデフォルト値を含めます。
LibreOffice、Python、カーネルなどについて尋ねました。
LibreOfficeは、次のようなバージョン情報を生成します。
$ libreoffice --version
LibreOffice 5.2.6.2 20m0(Build:2)
バージョン番号を抽出するには:
$ libreoffice --version | cut -d' ' -f2
5.2.6.2
Pythonの場合:
$ python -c 'import platform; print(platform.python_version())'
2.7.13
カーネルバージョンを取得するには、uname
を使用します。
$ uname -r
4.9.0-2-AMD64
バージョン番号を比較する代わりに、機能自体を直接テストできます。 declare -A
は、2
を認識しない場合は-A
(少なくともBash 3.2で)を返すので、テストします(エラーも出力します)。
unset assoc
if ! declare -A assoc ; then
echo "associative arrays not supported!"
exit 1
fi
(var
が非連想配列の場合、declare -A var
も失敗するため、最初にunset
になります。)
誰もがBashの機能をバックポートするとは思いませんが、一般的には、バージョンではなく機能をチェックする方が適切です。 Bashの場合でも、誰かが限定された機能のみを備えたバージョンをコンパイルする可能性があります...
バージョン番号をテストするより一般的なケースには、2つの部分があります。1)テストする正しいバージョン番号を見つける方法、2)別の値と比較する方法。
最初はもっと難しいものです。多くのプログラムは--version
や-v
のようなコマンドラインフラグでバージョン番号を伝えますが、出力形式はさまざまであり、プログラムでバージョン番号を選択するのは難しい場合があります。次に、同じプログラムの複数のバージョンが同時にインストールされる可能性があるという問題があります。
2番目は、バージョン番号の形式に関する知識に依存します。 dpkg
は比較できます Debianスタイルのバージョン番号 (これには semver サブセットとしてのタイプバージョンが含まれると思います):
if dpkg --compare-versions 4.3.30 ge 4.0.0 ; then
echo "it's version 4.x"
fi
または、上記を結合するだけです:
bashver=$( bash --version | sed -Ee 's/GNU bash, version ([0-9.]+).*/\1/;q' )
if dpkg --compare-versions "$bashver" ge 4.0.0 ; then
echo "'bash' in your path is version 4.x"
fi
達成したいものにアプローチする方法はいくつかあります。
$BASH_VERSION
変数の内容を確認するだけで十分です。個人的に私は次のようなサブシェルを使用します:
$ (read -d "." version trash <<< $BASH_VERSION; echo "$version" )
4
Here-docの<<<
構文は、/bin/sh
と共に使用する場合、移植性がないことに注意してください。これは、Ubuntuではダッシュであり、別のシステムでは別のものになる可能性があります
別の方法は、caseステートメントまたはifステートメントを使用することです。個人的に、私はこれをします:
bash-4.3$ case $BASH_VERSION in 4.*) echo "Can use associative arrays";; ?) echo "can't use associative arrays" ;; esac
Can use associative arrays
おそらく移植性のために、おそらく最初にそのような変数が[ -n $BASH_VERSION ]
のようなもので設定されているかどうかをチェックする必要があるでしょう。
これは、スクリプトで使用する関数として完全に書き換えることができます。長い行:
#!/bin/bash
version_above_4(){
# check if $BASH_VERSION is set at all
[ -z $BASH_VERSION ] && return 1
# If it's set, check the version
case $BASH_VERSION in
4.*) return 0 ;;
?) return 1;;
esac
}
if version_above_4
then
echo "Good"
else
echo "No good"
fi
これはワンライナーではありませんが、はるかに優れています。量より質。
そのためには、apt-cache policy
の出力を次のようにフィルタリングする必要があります
$ apt-cache policy bash | awk -F '[:.]' '/Installed:/{printf "%s\n",substr($2,2)}'
4
dpkg-query
は、awk
を介したいくつかのフィルタリングにも役立ちます。
$ dpkg-query -W bash | awk '{print substr($2,1,1)}'
4
dpkg
またはapt
がシステム(たとえば、RHELまたはFreeBSD)にインストールされていない場合、それは何の役にも立たないため、これは移植性がないことに注意してください。
これを回避する1つの方法は、単に連想配列を使用して、bash
が使用できないときに終了することです。 set -e
の下の#!/bin/bash
行は、スクリプトが連想配列を使用できない場合にスクリプトを終了できるようにします。
そのためには、ユーザーに「bashバージョン4.3以降が本当に必要です。そうしないと、スクリプトが機能しません」と明示的にユーザーに伝える必要があります。責任はユーザーにありますが、これは実際にはソフトウェア開発への良いアプローチではないと主張する人もいるかもしれません。
bash
スクリプトは、構文がBourne Shellと互換性がないため、移植できません。書いているスクリプトがUbuntuだけでなく、さまざまなシステムで使用される場合、すべての希望を捨てて、連想配列以外のものを使用する方法を見つけてください。これには、2つの配列を持つことや、構成ファイルを解析することが含まれます。構文が少なくともbash
より移植性の高い別の言語、PerlまたはPythonへの切り替えも検討してください。
Stack Overflowで答えを引き出すスクリプトを開発しました。これらの回答の1つは、2004年にDKMSアプリケーションのバージョン番号の比較を作成するDell従業員につながりました。
以下のbashスクリプトは、chmod a+x script-name
コマンドを使用して実行可能としてマークする必要があります。名前/usr/local/bin/testver
を使用しています:
#!/bin/bash
# NAME: testver
# PATH: /usr/local/bin
# DESC: Test a program's version number >= to passed version number
# DATE: May 21, 2017. Modified August 5, 2019.
# CALL: testver Program Version
# PARM: 1. Program - validated to be a command
# 2. Version - validated to be numberic
# NOTE: Extracting version number Perl one-liner found here:
# http://stackoverflow.com/questions/16817646/extract-version-number-from-a-string
# Comparing two version numbers code found here:
# http://stackoverflow.com/questions/4023830/how-compare-two-strings-in-dot-separated-version-format-in-bash
# Map parameters to coder-friendly names.
Program="$1"
Version="$2"
# Program name must be a valid command.
command -v $Program >/dev/null 2>&1 || { echo "Command: $Program not found. Check spelling."; exit 99; }
# Passed version number must be valid format.
if ! [[ $Version =~ ^([0-9]+\.?)+$ ]]; then
echo "Version number: $Version has invalid format. Aborting.";
exit 99
fi
InstalledVersion=$( "$Program" --version | Perl -pe '($_)=/([0-9]+([.][0-9]+)+)/' )
# echo "Installed Version: $InstalledVersion"
if [[ $InstalledVersion =~ ^([0-9]+\.?)+$ ]]; then
l=(${InstalledVersion//./ })
r=(${Version//./ })
s=${#l[@]}
[[ ${#r[@]} -gt ${#l[@]} ]] && s=${#r[@]}
for i in $(seq 0 $((s - 1))); do
# echo "Installed ${l[$i]} -gt Test ${r[$i]}?"
[[ ${l[$i]} -gt ${r[$i]} ]] && exit 0 # Installed version > test version.
[[ ${l[$i]} -lt ${r[$i]} ]] && exit 1 # Installed version < test version.
done
exit 0 # Installed version = test version.
else
echo "Invalid version number found for command: $Program"
exit 99
fi
echo "testver - Unreachable code has been reached!"
exit 255