1.使用$BASH_VERSION

1.使用$BASH_VERSION

我需要測試 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 腳本中,我想以最優雅/高效/可讀的方式進行單行測試,但也接受其他方法。

答案1

嘗試:

$ [ "${BASH_VERSINFO:-0}" -ge 4 ] && echo "bash supports associative arrays"
bash supports associative arrays

BASH_VERSINFO是一個只讀數組變量,其成員保存此 bash 實例的版本資訊。由於它是在 bash 2.0 中引入的,因此您將遇到的所有 bash 版本都可能支援它。但是,為了謹慎起見,我們0為任何未設定此變數的早期版本 bash提供預設值 of 。

從其他程式中提取版本信息

您詢問了 LibreOffice、Python、內核等。

LibreOffice 產生的版本資訊如下所示:

$ libreoffice --version
LibreOffice 5.2.6.2 20m0(Build:2)

要擷取版本號:

$ libreoffice --version | cut -d' ' -f2
5.2.6.2

對於蟒蛇:

$ python -c 'import platform; print(platform.python_version())'
2.7.13

若要取得核心版本,請使用uname

$ uname -r
4.9.0-2-amd64

答案2

您可以直接測試功能本身,而不是比較版本號。如果它不能識別 則declare -A返回2(至少在 Bash 3.2 中)-A,因此進行測試(它也會列印錯誤):

unset assoc
if ! declare -A assoc ; then
    echo "associative arrays not supported!"
    exit 1
fi

(如果是非關聯數組declare -A var也會失敗,所以首先。)varunset

雖然我不認為有人會向後移植 Bash 中的功能,但一般來說,檢查功能而不是版本更合適。即使在 Bash 的情況下,有人也可能編譯一個只有有限功能的版本...


測試版本號的更一般情況有兩個部分:1)如何找到要測試的正確版本號,2)如何將其與另一個值進行比較。

第一個是比較困難的一個。許多程式使用命令列標誌(如--version或 )來告知其版本號-v,但輸出格式各不相同,並且以程式設計方式選擇版本號可能很困難。然後存在可能同時安裝同一程式的多個版本的問題。

第二個取決於對版本號格式的一些了解。dpkg可以比較Debian 風格的版本號(我認為包括塞姆弗輸入版本作為子集):

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

答案3

有幾種方法可以實現您想要實現的目標。

1.使用$BASH_VERSION

只需查看$BASH_VERSION變數中的內容就足夠了。就我個人而言,我會像這樣使用 subshel​​l:

$ (read -d "." version trash <<< $BASH_VERSION; echo "$version" )
4

請注意,<<<如果您要將其與/bin/shUbuntu 上的 Dash 一起使用,則here-doc的語法不可移植,在不同的系統上可能是其他東西

另一種方法是透過 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

這不是一句單行話,儘管這要好得多。質而不是數量。

2.檢查安裝了什麼

為此,您需要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或安裝了它(例如,RHEL 或 FreeBSD),它不會對您有任何好處。apt

3. 如果出現錯誤,使用 set -e 退出腳本

解決這個問題的一種方法是簡單地繼續使用關聯數組,並在bash無法使用它們時退出。如果腳本無法使用關聯數組,set -e則下面的行將#!/bin/bash允許腳本退出。

這將要求您明確地告訴使用者:「嘿,您確實需要 bash 版本 4.3 或更高版本,否則腳本將無法運作」。那麼責任就落在使用者身上,儘管有些人可能會認為這並不是一個真正好的軟體開發方法。

4. 放棄所有希望,編寫可移植的、符合 POSIX 標準的腳本

bash腳本不可移植,因為其語法與 Bourne shell 不相容。如果您正在編寫的腳本將在一系列不同的系統上使用,而不僅僅是 Ubuntu,那麼請放棄所有希望,並找到使用關聯數組以外的其他系統的方法。這可能包括擁有兩個陣列或解析設定檔。也可以考慮切換到不同的語言,Perl 或 Python,其中語法至少比bash.

答案4

不可能使用單行腳本,但可以使用 bash 腳本

我開發了一個腳本,該腳本借鑒了 Stack Overflow 中的答案。其中一個答案導致戴爾員工在 2004 年撰寫了 DKMS 應用程式版本號比較的文章。

程式碼

需要使用命令將下面的 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

相關內容