1. Utilize$BASH_VERSION

1. Utilize$BASH_VERSION

Preciso testar se o número da versão do Bash é >= para um número específico. Por exemplo eu tenho:

$ 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.

Para usar arrays associativos, o número da versão do bash deve ser >=4.

No meu script bash, gostaria de fazer um teste de uma linha da maneira mais elegante/eficiente/legível possível, mas outras abordagens também são aceitas.

Responder1

Tentar:

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

BASH_VERSINFOé uma variável de array somente leitura cujos membros contêm informações de versão para esta instância do bash. Como foi introduzido no bash 2.0, provavelmente é compatível com todas as versões do bash que você encontrar. Mas, para sermos cautelosos, incluímos um valor padrão of 0para qualquer versão anterior do bash para a qual esta variável não esteja definida.

Extraindo informações de versão de outros programas

Você perguntou sobre LibreOffice, Python, kernel, etc.

O LibreOffice produz informações de versão semelhantes a:

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

Para extrair o número da versão:

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

Para píton:

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

Para obter a versão do kernel, use uname:

$ uname -r
4.9.0-2-amd64

Responder2

Em vez de comparar os números de versão, você pode testar diretamente o próprio recurso. declare -Aretorna 2(pelo menos no Bash 3.2) se não reconhecer -A, então teste isso (também imprime um erro):

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

( declare -A vartambém falha se varfor uma matriz não associativa, então unsetprimeiro.)

Embora eu realmente não presuma que alguém fará backport de recursos no Bash, em geral é mais apropriado verificar os recursos, não as versões. Mesmo no caso do Bash, alguém pode compilar uma versão com recursos limitados...


O caso mais geral de teste de números de versão tem duas partes: 1) como encontrar o número de versão correto para testar e 2) como compará-lo com outro valor.

O primeiro é o mais difícil. Muitos programas informam seu número de versão com um sinalizador de linha de comando como --versionou -v, mas o formato de saída varia e pode ser difícil escolher programaticamente o número da versão. Depois, há a questão de possivelmente ter várias versões do mesmo programa instaladas ao mesmo tempo.

A segunda depende de algum conhecimento do formato dos números de versão. dpkgpode compararNúmeros de versão no estilo Debian(que eu acho que incluisempredigite versões como subconjunto):

if dpkg --compare-versions 4.3.30 ge 4.0.0 ; then
    echo "it's version 4.x"
fi

Ou, apenas para combinar o acima:

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

Responder3

Existem algumas maneiras de abordar o que você deseja alcançar.

1. Utilize$BASH_VERSION

É suficiente apenas ver o que está na $BASH_VERSIONvariável. Pessoalmente, eu usaria subshell assim:

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

Observe que <<<a sintaxe para here-doc não é portátil, se você for usá-la com /bin/sh, que é Dash no Ubuntu e pode ser outra coisa em um sistema diferente

A maneira alternativa é por meio da instrução case ou da instrução if. Pessoalmente, eu faria isso:

bash-4.3$ case $BASH_VERSION in 4.*) echo "Can use associative arrays";; ?) echo "can't use associative arrays" ;; esac
Can use associative arrays

Provavelmente por uma questão de portabilidade, você provavelmente deveria verificar se essa variável está definida em primeiro lugar com algo como[ -n $BASH_VERSION ]

Isso pode ser totalmente reescrito como uma função a ser usada em um script. Algo muito longo como:

#!/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

Esta não é uma frase única, embora seja muito melhor. Qualidade acima de quantidade.

2. Verifique o que está instalado

Para isso você precisa filtrar a saída apt-cache policyassim

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

dpkg-querytambém pode ser útil com alguma filtragem via awk.

$ dpkg-query -W bash | awk '{print substr($2,1,1)}'   
4

Observe que isso não é portátil, pois se não houver dpkgou aptestiver instalado em um sistema (por exemplo, RHEL ou FreeBSD), não adiantará nada.

3. Use set -e para sair do script se houver um erro

Uma maneira de contornar isso é simplesmente usar matrizes associativas e sair quando bashnão puder usá-las. set -eA linha abaixo #!/bin/bashpermitirá que o script seja encerrado se o script não puder usar a matriz associativa.

Isso exigirá que você diga explicitamente ao usuário: "Ei, você realmente precisa do bash versão 4.3 ou superior, caso contrário o script não funcionará". Então a responsabilidade recai sobre o usuário, embora alguns possam argumentar que esta não é realmente uma boa abordagem para o desenvolvimento de software.

4. Abandone toda esperança e escreva scripts portáteis compatíveis com POSIX

bashscripts não são portáveis ​​porque sua sintaxe não é compatível com o Bourne Shell. Se o script que você está escrevendo for usado em vários sistemas diferentes, não apenas no Ubuntu, abandone todas as esperanças e encontre maneiras de usar algo diferente de matrizes associativas. Isso pode incluir ter duas matrizes ou analisar um arquivo de configuração. Considere também mudar para uma linguagem diferente, Perl ou Python, onde a sintaxe é pelo menos mais portável que bash.

Responder4

One-liner não é possível, mas um script bash é possível

Desenvolvi um script baseado em respostas no Stack Overflow. Uma dessas respostas levou um funcionário da Dell a escrever comparações de números de versão em 2004 para o aplicativo DKMS.

O código

O script bash abaixo precisa ser marcado como executável usando o comando chmod a+x script-name. Estou usando o nome /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

informação relacionada