ตรวจสอบว่าเวอร์ชั่น Bash เป็น> = ระบุหมายเลขเวอร์ชั่นหรือไม่


12

ฉันต้องการทดสอบว่าหมายเลขเวอร์ชัน 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_VERSIONและ$BASH_VERSINFOตัวแปรหรือไม่
ขับขี่เหล็ก

@steeldriver เลขที่จะเป็นคำตอบที่ยอมรับได้ในกรณีทุบตีเฉพาะถ้าคุณต้องการโพสต์ อย่างไรก็ตามในกรณีอื่นตัวแปรสิ่งแวดล้อมอาจไม่สามารถใช้ได้
WinEunuuchs2Unix

โดยวิธีการที่เกี่ยวข้อง: askubuntu.com/questions/39309/ …
Sergiy Kolodyazhnyy

@SergiyKolodyazhnyy ที่เกี่ยวข้องกับการทุบตีเท่านั้น แม้ว่าฉันกำลังมองหาทุบตีหนึ่งซับหรือสคริปต์ / ฟังก์ชั่นการตรวจสอบหมายเลขรุ่นทุบตีเท่านั้นไม่ใช่เป้าหมายสูงสุด รูทีนทั่วไปเพื่อตรวจสอบโปรแกรมทั้งหมดโดยต่อท้าย--versionและทดสอบผลลัพธ์เป็นความตั้งใจดั้งเดิม ฉันแก้ไขคำถามแล้ว
WinEunuuchs2Unix

รูปแบบหมายเลขเวอร์ชันแตกต่างกันไปตามโปรแกรม วิธีที่พวกเขารายงานรายละเอียดเวอร์ชันนั้นแตกต่างกันไปด้วย ไม่ใช่เรื่องง่ายที่จะขอวิธีตรวจสอบเวอร์ชันของโปรแกรมแบบสุ่ม คำถามนี้กว้างเกินไป
muru

คำตอบ:


16

ลอง:

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

BASH_VERSINFOเป็นตัวแปรอาร์เรย์แบบอ่านอย่างเดียวซึ่งสมาชิกเก็บข้อมูลรุ่นสำหรับอินสแตนซ์ของ bash นี้ เนื่องจากมันถูกนำมาใช้กับ bash 2.0 เป็นไปได้ว่ามันรองรับ 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 -c 'import platform; print(platform.python_version())'
2.7.13

ในการรับรุ่นเคอร์เนลให้ใช้uname:

$ uname -r
4.9.0-2-amd64

คำตอบที่ดี! เพียงแค่ทราบว่าคุณuname -rคือ "4.9.0-2-amd64" ซึ่งสามารถทดสอบได้ดีกว่าของฉัน "4.11.1-041101-generic" ด้วยการทดสอบทุบตีปกติเมื่อในความเป็นจริงหมายเลขรุ่นของฉันยิ่งใหญ่กว่า
WinEunuuchs2Unix

2
@ WinEunuuchs2Unix เครื่องมือ Python สามารถเปรียบเทียบสตริงรุ่นได้อย่างถูกต้อง ดูการเปรียบเทียบสตริงรุ่นใน Python
wjandrea

John-- ตัวอย่างเช่นงูหลามจะสั้นลงด้วยซึ่งผลตอบแทน$ python --version Python 2.7.12@ wjandrea-- ขอบคุณสำหรับลิงก์ +1 บางทีฉันอาจสร้างตารางของชื่อโปรแกรมทั้งหมดและหมายเลขรุ่นที่น้อยที่สุด จากนั้นส่งตารางไปยังสำเนาของpythonลิงก์ที่คุณให้ไว้ เพราะคุณสามารถเรียก Python ที่คอมไพล์แล้วเท่านั้นที่grubคิดว่าไบนารีมีอยู่เพื่อทำสิ่งนี้หรือเป็นไปได้ในเชลล์
WinEunuuchs2Unix

9

แทนที่จะเปรียบเทียบหมายเลขรุ่นคุณสามารถทดสอบโดยตรงสำหรับคุณสมบัตินั้น ๆ 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และจะล้มเหลวหาก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

หรือเพียงเพื่อรวมด้านบน:

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

มีสองวิธีในการเข้าถึงสิ่งที่คุณต้องการบรรลุ

1. ใช้ $ BASH_VERSION

มันเพียงพอแล้วที่จะเห็นว่ามีอะไรอยู่ใน$BASH_VERSIONตัวแปร โดยส่วนตัวฉันจะใช้ subshell อย่างเช่น:

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

โปรดทราบว่า<<<ไวยากรณ์สำหรับ here-doc ไม่ใช่แบบพกพาหากคุณจะใช้กับ/bin/shซึ่งเป็น Dash บน Ubuntu และอาจเป็นอย่างอื่นในระบบอื่น

ทางเลือกคือผ่านคำสั่งกรณีหรือถ้าคำสั่ง โดยส่วนตัวฉันจะทำสิ่งนี้:

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-queryawkนอกจากนี้ยังสามารถเข้ามามีประโยชน์กับบางกรองผ่าน

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

โปรดทราบว่านี่ไม่ใช่การพกพาเนื่องจากหากไม่มีdpkgหรือaptติดตั้งในระบบ (เช่น RHEL หรือ FreeBSD) ระบบจะไม่ทำสิ่งใดให้คุณ

3. ใช้ set -e เพื่อออกจาก script หากมีข้อผิดพลาด

วิธีหนึ่งในการหลีกเลี่ยงมันก็คือการใช้อาเรย์แบบเชื่อมโยงและเลิกใช้เมื่อbashไม่สามารถใช้งานได้ set -eบรรทัดด้านล่าง#!/bin/bashจะอนุญาตให้สคริปต์ออกหากสคริปต์ไม่สามารถใช้อาเรย์แบบเชื่อมโยงได้

สิ่งนี้จะทำให้คุณต้องบอกผู้ใช้อย่างชัดเจนว่า: "เฮ้คุณต้องทุบตีเวอร์ชั่น 4.3 ขึ้นไปมิฉะนั้นสคริปต์จะไม่ทำงาน" ความรับผิดชอบนั้นขึ้นอยู่กับผู้ใช้แม้ว่าบางคนอาจแย้งว่านี่ไม่ใช่วิธีที่ดีในการพัฒนาซอฟต์แวร์

4. ละทิ้งความหวังและเขียนสคริปต์แบบพกพาที่สอดคล้องกับ POSIX

bashสคริปต์ไม่สามารถเคลื่อนย้ายได้เนื่องจากไวยากรณ์ไม่สามารถทำงานร่วมกับ Bourne shell ได้ หากสคริปต์ที่คุณกำลังเขียนจะถูกนำไปใช้กับระบบที่แตกต่างกันไม่ใช่เฉพาะ Ubuntu เพียงอย่างเดียวให้ละทิ้งความหวังทั้งหมดและหาวิธีใช้สิ่งอื่นนอกเหนือจากอาร์เรย์เชื่อมโยง ซึ่งอาจรวมถึงการมีสองอาร์เรย์หรือแยกไฟล์การกำหนดค่า ยังพิจารณาเปลี่ยนไปใช้ภาษาที่แตกต่างกัน, Perl bashหรืองูหลามที่ไวยากรณ์อย่างน้อยกว่าแบบพกพา


อาเรย์แบบเชื่อมโยงเป็นวินาทีของ "สองอาร์เรย์" ตามที่คุณแนะนำในส่วนที่ 4 มันมีจุดประสงค์เพียงอย่างเดียวคือการเก็บคีย์ "path / to / file-name" และค่าคือดัชนีภายในอาเรย์หลัก อาเรย์แบบเชื่อมโยงถูกสร้างขึ้นเพื่อเพิ่มความเร็วในการค้นหาในอาเรย์แบบดัชนีปกติซึ่งต่อเนื่องกันในปัจจุบัน แม้ว่าฉันจะสนใจ Python อยู่แล้ว แต่ความเข้ากันได้ของ bash ปัจจุบันนั้นมุ่งเน้นไปที่ Ubuntu และ Bash สำหรับ Windows 10 ฉันชอบสคริปต์ของคุณที่สามารถปรับแต่งได้ ตัวอย่างเช่นyad --versionผลตอบแทน0.37.0 (GTK+ 3.18.9)แต่ลูกเล่นใหม่ ๆ 0.39อยู่ในขณะนี้
WinEunuuchs2Unix

คำตอบที่ดีและเป็นประโยชน์ ขอบคุณ!
qodeninja

2

หนึ่งซับไม่สามารถทำได้ แต่สคริปต์ทุบตีเป็นไปได้

ฉันพัฒนาสคริปต์ที่ดึงคำตอบใน Stack Overflow หนึ่งในคำตอบเหล่านั้นนำไปสู่การเปรียบเทียบการเขียนหมายเลขรุ่นพนักงานของ Dell ในปี 2004 สำหรับแอปพลิเคชัน DKMS

รหัส

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
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.