Bash sürümünün> = verilen sürüm numarası olup olmadığını kontrol edin


12

Bash sürüm numarasının belirli bir sayı için> = olup olmadığını test etmem gerekiyor. Örneğin:

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

İlişkilendirilebilir dizileri kullanabilmek için, bash sürüm numarası> = 4 olmalıdır.

Benim bash senaryomda mümkün olan en zarif / verimli / okunabilir şekilde tek astarlı bir test yapmak istiyorum, ancak diğer yaklaşımlar da kabul ediliyor.


$BASH_VERSIONVe $BASH_VERSINFOdeğişkenlerine baktınız mı ?
steeldriver

@steeldriver Hayır. Eğer göndermek isterseniz, bash'a özel bir durumda kabul edilebilir bir cevap olacaktır. Ancak, diğer durumlarda çevresel değişkenler mevcut olmayabilir.
WinEunuuchs2Unix


@SergiyKolodyazhnyy sadece bash ile ilgilidir. Her ne kadar bash tek satırlı veya script / fonksiyon arıyorsanız sadece bash sürüm numarasını kontrol etmek nihai hedef değildir. --versionÇıktı ekleyerek ve test ederek tüm programları kontrol etmek için genel bir rutin orijinal amaçtı. Soruyu buna göre düzenledim.
WinEunuuchs2Unix

Sürüm numarası biçimleri programlar arasında büyük farklılıklar gösterir. Sürüm ayrıntılarını bildirme yöntemleri de çok farklıdır. Rastgele bir programın sürümünü kontrol etmenin bir yolunu istemek pratik değildir. Bu soru çok geniş.
muru

Yanıtlar:


16

Deneyin:

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

BASH_VERSINFOüyeleri bu bash örneği için sürüm bilgilerini tutan salt okunur bir dizi değişkenidir. Bash 2.0 ile tanıtıldığından, muhtemelen karşılaşacağınız tüm bash sürümleri tarafından desteklenmektedir. Ancak, dikkatli olmak 0için, bu değişkenin ayarlanmadığı herhangi bir önceki sürüm bash için varsayılan değerini ekliyoruz.

Diğer programlardan sürüm bilgilerini çıkarma

LibreOffice, Python, çekirdek vb. Hakkında sorular sordunuz.

LibreOffice, şuna benzer sürüm bilgileri üretir:

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

Sürüm numarasını çıkarmak için:

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

Python için:

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

Çekirdek sürümünü edinmek için şunu kullanın uname:

$ uname -r
4.9.0-2-amd64

Harika cevaplar! Sadece uname -rbenim sürüm numaram daha büyük olduğunda düzenli bash testi ile benim "daha büyük test edebilirsiniz" 4.9.0-2-amd64 " olduğunu bir not .
WinEunuuchs2Unix

2
@ WinEunuuchs2Unix Python araçları sürüm dizelerini doğru şekilde karşılaştırabilir. Bkz. Sürüm dizelerini Python
wjandrea'da karşılaştırın

John-- Python örneği $ python --versiongeri döndürülebilir Python 2.7.12. @ wjandrea-- +1 bağlantı için teşekkürler. Belki de tüm program adları ve en az sürüm numaralarından oluşan bir tablo oluşturabilirim. Ardından tabloyu, sağladığınız pythonbağlantının değiştirilmiş bir kopyasına iletin. Çünkü sadece derlenmiş Python tarafından çağrılabilir çünkü grubbunu yapmak için bir ikili var olduğunu veya kabuğunda mümkün olduğunu düşünürdünüz.
WinEunuuchs2Unix

9

Sürüm numaralarını karşılaştırmak yerine, doğrudan özelliğin kendisini test edebilirsiniz. tanımazsa declare -Adöndürür 2(en azından Bash 3.2'de) -A, bu yüzden test edin (ayrıca bir hata yazdırır):

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

( çağrışımsal olmayan bir dizi ise declare -A varde başarısız olur var, bu unsetyüzden önce dizilir.)

Kimsenin Bash'deki özellikleri geri vereceğini sanmıyorum, genel olarak sürümleri değil özellikleri kontrol etmek daha uygun. Bash'ın durumunda bile, birisi sadece sınırlı özelliklere sahip bir sürüm derleyebilir ...


Sürüm numaralarını test etmenin daha genel durumu iki bölümden oluşur: 1) test edilecek doğru sürüm numarasının nasıl bulunacağı ve 2) başka bir değerle nasıl karşılaştırılacağı.

Birincisi daha zor olanı. Birçok program sürüm numaralarını --versionveya gibi bir komut satırı işaretiyle söyler -v, ancak çıktı biçimi değişir ve program numarasıyla sürüm numarasını seçmek zor olabilir. Sonra aynı programın aynı anda birkaç sürümünün yüklü olması sorunu var.

İkincisi, sürüm numaralarının formatı hakkındaki bazı bilgilere bağlıdır. dpkgkarşılaştırabilirsiniz Debian tarzı sürüm numaraları (ı içerir düşünüyorum semver alt kümesi olarak türü versiyonlarını):

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

Veya sadece yukarıdakileri birleştirmek için:

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

5

Ulaşmak istediğiniz şeye yaklaşmanın birkaç yolu var.

1. $ BASH_VERSION kullanın

$BASH_VERSIONDeğişkende ne olduğunu görmek yeterlidir . Şahsen ben böyle subshell kullanmak istiyorum:

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

Not <<<birlikte kullandığınız için gidiyoruz eğer burada-doc için sözdizimi, taşınabilir değildir /bin/shDash Ubuntu üzerinde ve farklı bir sistem üzerinde başka bir şey olabilir ki,

Alternatif yol, case deyimi veya if deyimi yoluyladır. Şahsen ben bunu yapardım:

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

Muhtemelen taşınabilirlik uğruna, muhtemelen böyle bir değişkenin ilk etapta bile ayarlandığını kontrol etmelisiniz. [ -n $BASH_VERSION ]

Bu tamamen bir komut dosyasında kullanılacak işlev olarak yeniden yazılabilir. Uzun bir şey:

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

Bu çok daha iyi olmasına rağmen, bu bir astar değildir. Miktar üzerinden kalite.

2. Neyin yüklü olduğunu kontrol edin

Eğer filtre çıkışının gerekir Bunun için apt-cache policyşöyle

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

dpkg-querybazı filtreleme ile de kullanışlı olabilir awk.

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

Bunun taşınabilir olmadığını unutmayın, çünkü bir sistemde yüklü dpkgveya aptyüklü değilse (örneğin, RHEL veya FreeBSD), size hiçbir faydası olmaz.

3. Bir hata varsa komut dosyasından çıkmak için set -e komutunu kullanın

Etrafında dolaşmanın bir yolu, basitçe bir çağrışımsal dizileri bashkullanmak ve bunları kullanamadıklarında çıkmaktır. set -eAşağıdaki satır #!/bin/bash, komut dosyası ilişkilendirilebilir dizi kullanamıyorsa komut dosyasının kapanmasına izin verir.

Bu, kullanıcıya açıkça şunları söylemenizi gerektirir: "Hey, gerçekten bash 4.3 veya daha üst bir sürüme ihtiyacınız var, aksi takdirde komut dosyası çalışmaz". O zaman sorumluluk kullanıcıya aittir, ancak bazıları bunun yazılım geliştirmeye gerçekten iyi bir yaklaşım olmadığını iddia edebilir.

4. Tüm umutları bırakın ve taşınabilir, POSIX uyumlu komut dosyaları yazın

bashkomut dosyaları taşınabilir değildir, çünkü sözdizimi Bourne kabuğuyla uyumlu değildir. Yazdığınız komut dosyası yalnızca Ubuntu'da değil, farklı sistemlerde kullanılacaksa, tüm umudunuzu bırakın ve ilişkilendirilebilir diziler dışında bir şey kullanmanın yollarını bulun. Bu, iki diziye sahip olmayı veya bir yapılandırma dosyasını ayrıştırmayı içerebilir. Ayrıca sözdiziminin en az daha taşınabilir olduğu farklı bir dile, Perl veya Python'a geçmeyi düşünün bash.


İlişkilendirilebilir dizi, 4. bölümde önerdiğiniz gibi "iki dizinin" ikincisidir. Bunun tek amacı "path / to / file-name" anahtarını tutmaktır ve değer, ana dizi içindeki dizindir. İlişkilendirilebilir dizi, aramaları şu anda sıralı olan normal dizinlenmiş diziye hızlandırmak için oluşturulmuştur. Yine de Python üzerinde gözüm olmasına rağmen, şu anki bash uyumluluğum Ubuntu ve belki de Windows 10 için Bash üzerine odaklanmış. Örneğin, yad --versioniadeler 0.37.0 (GTK+ 3.18.9)ancak yeni özellikler şu anda mevcut 0.39.
WinEunuuchs2Unix

harika ve yararlı bir cevap. teşekkür ederim!
qodeninja

2

Tek satır mümkün değil ancak bash betiği mümkün

Stack Overflow'da cevapları çizen bir senaryo geliştirdim. Bu yanıtlardan biri, DKMS uygulaması için 2004 yılında bir Dell Çalışanının sürüm numarası karşılaştırmaları yazmasına yol açtı.

Kod

Aşağıdaki bash komut dosyasının komut kullanılarak yürütülebilir olarak işaretlenmesi gerekir chmod a+x script-name. Adı kullanıyorum /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
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.