检查 Bash 版本是否 >= 给定的版本号

Win*_*nix 17 command-line versions bash scripts

我需要测试 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.
Run Code Online (Sandbox Code Playgroud)

为了使用关联数组,bash 版本号必须 >=4。

在我的 bash 脚本中,我想以最优雅/高效/可读的方式进行单行测试,但也接受其他方法。

Joh*_*024 21

尝试:

$ [ "${BASH_VERSINFO:-0}" -ge 4 ] && echo "bash supports associative arrays"
bash supports associative arrays
Run Code Online (Sandbox Code Playgroud)

BASH_VERSINFO是一个只读数组变量,其成员保存此 bash 实例的版本信息。由于它是随 bash 2.0 引入的,因此您可能会遇到的所有 bash 版本都支持它。但是,谨慎起见,0对于未设置此变量的任何早期版本的 bash ,我们都包含一个默认值。

从其他程序中提取版本信息

您询问了 LibreOffice、Python、内核等。

LibreOffice 生成的版本信息如下所示:

$ libreoffice --version
LibreOffice 5.2.6.2 20m0(Build:2)
Run Code Online (Sandbox Code Playgroud)

提取版本号:

$ libreoffice --version | cut -d' ' -f2
5.2.6.2
Run Code Online (Sandbox Code Playgroud)

对于蟒蛇:

$ python -c 'import platform; print(platform.python_version())'
2.7.13
Run Code Online (Sandbox Code Playgroud)

要获取内核版本,请使用uname

$ uname -r
4.9.0-2-amd64
Run Code Online (Sandbox Code Playgroud)

  • @WinEunuuchs2Unix Python 工具可以准确比较版本字符串。请参阅 [比较 Python 中的版本字符串](http://stackoverflow.com/q/11887762/4518341) (2认同)

ilk*_*chu 10

您可以直接测试功能本身,而不是比较版本号。如果它不识别,则declare -A返回2(至少在 Bash 3.2 中)-A,因此对其进行测试(它还会打印错误):

unset assoc
if ! declare -A assoc ; then
    echo "associative arrays not supported!"
    exit 1
fi
Run Code Online (Sandbox Code Playgroud)

declare -A var如果var是非关联数组,也会失败,所以unset它首先。)

虽然我真的不认为任何人会在 Bash 中向后移植功能,但通常检查功能更合适,而不是版本。即使在 Bash 的情况下,有人可能会编译一个只有有限功能的版本......


测试版本号的更一般情况有两个部分:1) 如何找到要测试的正确版本号,以及 2) 如何将它与另一个值进行比较。

第一个是比较困难的。许多程序使用命令行标志(如--version或 )告诉它们的版本号-v,但输出格式各不相同,以编程方式选择版本号可能很困难。然后是可能同时安装同一程序的多个版本的问题。

第二个取决于对版本号格式的一些了解。dpkg可以比较Debian 风格的版本号(我认为包括semver类型版本作为子集):

if dpkg --compare-versions 4.3.30 ge 4.0.0 ; then
    echo "it's version 4.x"
fi
Run Code Online (Sandbox Code Playgroud)

或者,只是结合上述内容:

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
Run Code Online (Sandbox Code Playgroud)


Ser*_*nyy 5

有几种方法可以实现您想要实现的目标。

1. 使用 $BASH_VERSION

只需查看$BASH_VERSION变量中的内容就足够了。我个人会像这样使用子shell:

$ (read -d "." version trash <<< $BASH_VERSION; echo "$version" )
4
Run Code Online (Sandbox Code Playgroud)

请注意,<<<here-doc 的语法不可移植,如果您打算将它与 一起使用/bin/sh,它在 Ubuntu 上是 Dash,在不同系统上可能是其他东西

另一种方法是通过 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
Run Code Online (Sandbox Code Playgroud)

可能是为了可移植性,您可能应该检查是否一开始就设置了这样的变量,例如 [ -n $BASH_VERSION ]

这完全可以重写为要在脚本中使用的函数。一些很长的行:

$ (read -d "." version trash <<< $BASH_VERSION; echo "$version" )
4
Run Code Online (Sandbox Code Playgroud)

这不是单线,虽然这要好得多。质量而不是数量。

2.检查安装了什么

为此,您需要apt-cache policy像这样过滤输出

$ apt-cache policy bash | awk -F '[:.]' '/Installed:/{printf "%s\n",substr($2,2)}'
4
Run Code Online (Sandbox Code Playgroud)

dpkg-query也可以通过一些过滤来派上用场awk

$ dpkg-query -W bash | awk '{print substr($2,1,1)}'   
4
Run Code Online (Sandbox Code Playgroud)

请注意,这不是可移植的,因为如果没有dpkgapt安装在系统上(例如,RHEL 或 FreeBSD),它对您没有任何好处。

3.如果出现错误,使用 set -e 退出脚本

绕过它的一种方法是简单地继续使用关联数组,并在bash无法使用它们时退出。如果脚本不能使用关联数组,set -e下面的#!/bin/bash行将允许脚本退出。

这将需要您明确告诉用户:“嘿,您确实需要 bash 4.3 或更高版本,否则脚本将无法运行”。然后责任在于用户,尽管有些人可能会争辩说这并不是真正的软件开发方法。

4. 放弃所有希望,编写可移植的、符合 POSIX 的脚本

bash脚本不可移植,因为它的语法与 Bourne shell 不兼容。如果您正在编写的脚本将用于一系列不同的系统,而不仅仅是 Ubuntu,那么放弃所有希望,并找到使用关联数组以外的其他东西的方法。这可能包括拥有两个数组或解析一个配置文件。还考虑切换到不同的语言,Perl 或 Python,其中语法至少比bash.