Kiểm tra xem phiên bản Bash có> = số phiên bản đã cho không


11

Tôi cần kiểm tra xem số phiên bản Bash có> = đến một số cụ thể không. Ví dụ tôi có:

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

Để sử dụng mảng kết hợp, số phiên bản bash phải> = 4.

Trong kịch bản bash của tôi, tôi muốn đưa vào thử nghiệm một lớp theo cách thanh lịch / hiệu quả / dễ đọc nhất có thể, nhưng các cách tiếp cận khác cũng được chấp nhận.


Bạn đã xem xét $BASH_VERSION$BASH_VERSINFOcác biến?
Steeldo

@steel ấn số. Đó sẽ là một câu trả lời chấp nhận được trong trường hợp cụ thể bash nếu bạn muốn đăng nó. Tuy nhiên, đối với các trường hợp khác, các biến môi trường có thể không có sẵn.
WinEunuuchs2Unix


@SergiyKolodyazhnyy chỉ liên quan đến bash. Mặc dù tôi đang tìm kiếm một bash one-liner hoặc script / function chỉ kiểm tra số phiên bản bash không phải là mục tiêu cuối cùng. Một thói quen chung để kiểm tra tất cả các chương trình bằng cách nối thêm --versionvà kiểm tra đầu ra là mục đích ban đầu. Tôi đã chỉnh sửa câu hỏi tương ứng.
WinEunuuchs2Unix

Định dạng số phiên bản rất khác nhau giữa các chương trình. Cách họ báo cáo chi tiết phiên bản cũng rất khác nhau. Đơn giản là không thực tế khi yêu cầu một cách để kiểm tra phiên bản chương trình ngẫu nhiên. Câu hỏi này quá rộng.
muru

Câu trả lời:


14

Thử:

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

BASH_VERSINFOlà một biến mảng chỉ đọc có các thành viên giữ thông tin phiên bản cho trường hợp bash này. Vì được giới thiệu với bash 2.0, nên có khả năng nó được hỗ trợ bởi tất cả các phiên bản bash mà bạn sẽ gặp. Nhưng, để thận trọng, chúng tôi bao gồm một giá trị mặc định là 0cho bất kỳ bash phiên bản nào trước đó mà biến này không được đặt.

Trích xuất thông tin phiên bản từ các chương trình khác

Bạn đã hỏi về LibreOffice, Python, kernel, v.v.

LibreOffice tạo ra thông tin phiên bản trông giống như:

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

Để trích xuất số phiên bản:

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

Đối với trăn:

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

Để có được phiên bản kernel, sử dụng uname:

$ uname -r
4.9.0-2-amd64

Câu trả lời tuyệt vời! Chỉ cần lưu ý rằng uname -r"4.9.0-2-amd64" của bạn có thể kiểm tra lớn hơn "chung chung 4.11.1-041101" của tôi với kiểm tra bash thông thường khi trong thực tế số phiên bản của tôi lớn hơn.
WinEunuuchs2Unix

2
@ WinEunuuchs2Unix Công cụ Python có thể so sánh chính xác các chuỗi phiên bản. Xem So sánh chuỗi phiên bản trong Python
wjandrea

John-- ví dụ python có thể được rút ngắn $ python --versionmà trả về Python 2.7.12. @ wjandrea-- cảm ơn vì liên kết +1. Có lẽ tôi có thể xây dựng một bảng gồm tất cả các tên chương trình và số phiên bản tối thiểu. Sau đó chuyển bảng tới một bản sao sửa đổi của pythonliên kết bạn cung cấp. Bởi vì chỉ có Python được biên dịch mới có thể được gọi bởi grubbạn sẽ nghĩ rằng một nhị phân tồn tại để làm điều này hoặc có thể trong shell.
WinEunuuchs2Unix

9

Thay vì so sánh số phiên bản, bạn có thể kiểm tra trực tiếp tính năng của chính nó. declare -Atrả về 2(ít nhất là trong Bash 3.2) nếu nó không nhận ra -A, vì vậy hãy kiểm tra xem (nó cũng in lỗi):

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

( declare -A varcũng thất bại nếu varlà một mảng không liên kết, vì vậy unsetnó là đầu tiên.)

Mặc dù tôi không thực sự cho rằng mọi người sẽ đưa vào các tính năng backport trong Bash, nói chung, việc kiểm tra các tính năng này, không phải là phiên bản phù hợp hơn. Ngay cả trong trường hợp của Bash, ai đó có thể biên dịch một phiên bản chỉ có các tính năng hạn chế ...


Trường hợp tổng quát hơn về số phiên bản thử nghiệm có hai phần: 1) cách tìm số phiên bản chính xác để kiểm tra và 2) cách so sánh nó với giá trị khác.

Đầu tiên là khó khăn hơn. Nhiều chương trình cho số phiên bản của họ với cờ dòng lệnh như --versionhoặc -v, nhưng định dạng đầu ra khác nhau và theo chương trình chọn số phiên bản có thể khó khăn. Sau đó, có vấn đề có thể có một số phiên bản của cùng một chương trình được cài đặt cùng một lúc.

Thứ hai phụ thuộc vào một số kiến ​​thức về định dạng của số phiên bản. dpkgcó thể so sánh các số phiên bản kiểu Debian (mà tôi nghĩ bao gồm các phiên bản loại semver như tập hợp con):

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

Hoặc, chỉ để kết hợp ở trên:

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

Có vài cách để tiếp cận những gì bạn muốn đạt được.

1. Sử dụng $ BASH_VERSION

Chỉ cần nhìn thấy những gì trong $BASH_VERSIONbiến. Cá nhân tôi sẽ sử dụng subshell như vậy:

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

Lưu ý rằng <<<cú pháp cho tài liệu ở đây không khả dụng, nếu bạn sẽ sử dụng nó với /bin/shDash, đó là Dash trên Ubuntu và có thể là một thứ khác trên một hệ thống khác

Cách khác là thông qua tuyên bố trường hợp hoặc nếu tuyên bố. Cá nhân, tôi sẽ làm điều này:

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

Có lẽ vì lợi ích của tính di động, có lẽ bạn nên kiểm tra xem biến đó thậm chí có được đặt ở vị trí đầu tiên với thứ gì đó như không [ -n $BASH_VERSION ]

Điều này hoàn toàn có thể được viết lại như là chức năng được sử dụng trong một kịch bản. Một cái gì đó dài dòng:

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

Đây không phải là một lót, mặc dù điều này là tốt hơn nhiều. Chất lượng hơn số lượng.

2. Kiểm tra những gì đã cài đặt

Cho rằng bạn cần phải lọc đầu ra apt-cache policynhư vậy

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

dpkg-querycũng có thể có ích với một số bộ lọc thông qua awk.

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

Lưu ý rằng đây không phải là thiết bị di động, vì nếu không có dpkghoặc aptđược cài đặt trên một hệ thống (ví dụ: RHEL hoặc FreeBSD), thì nó sẽ không giúp ích gì cho bạn.

3. Sử dụng set -e để thoát tập lệnh nếu có lỗi

Một cách để khắc phục nó chỉ đơn giản là đi trước một mảng kết hợp sử dụng và thoát ra khi bashkhông thể sử dụng chúng. set -edòng bên dưới #!/bin/bashsẽ cho phép tập lệnh thoát nếu tập lệnh không thể sử dụng mảng kết hợp.

Điều này sẽ yêu cầu bạn nói rõ ràng với người dùng: "Này, bạn thực sự cần bash phiên bản 4.3 trở lên, nếu không kịch bản sẽ không hoạt động". Sau đó, trách nhiệm thuộc về người dùng, mặc dù một số người có thể lập luận rằng đây không thực sự là một cách tiếp cận tốt để phát triển phần mềm.

4. Từ bỏ mọi hy vọng và viết các tập lệnh di động, tuân thủ POSIX

bashtập lệnh không khả dụng vì cú pháp của nó không tương thích với shell Bourne. Nếu tập lệnh mà bạn đang viết sẽ được sử dụng trên một loạt các hệ thống khác nhau, không chỉ riêng Ubuntu, thì hãy từ bỏ mọi hy vọng và tìm cách sử dụng thứ gì đó ngoài mảng kết hợp. Điều đó có thể bao gồm có hai mảng hoặc phân tích tệp cấu hình. Cũng xem xét chuyển sang một ngôn ngữ khác, Perl hoặc Python, trong đó cú pháp ít nhất là dễ mang theo hơn bash.


Mảng kết hợp là mảng thứ hai của "hai mảng" như bạn đề xuất trong phần 4. Mục đích duy nhất của nó là giữ khóa "path / to / file-name" và giá trị là chỉ mục trong mảng chính. Mảng kết hợp được tạo ra để tăng tốc độ tìm kiếm vào mảng được lập chỉ mục thông thường hiện đang tuần tự. Mặc dù tôi vẫn để mắt tới Python, khả năng tương thích bash hiện tại của tôi tập trung vào Ubuntu và có lẽ Bash cho Windows 10. Tôi thích tập lệnh của bạn có thể được tùy chỉnh. Ví dụ yad --versiontrả về 0.37.0 (GTK+ 3.18.9)nhưng các tính năng mới hiện đang có 0.39.
WinEunuuchs2Unix

câu trả lời tuyệt vời và hữu ích. cảm ơn bạn!
qodeninja

2

Không thể có một lớp lót nhưng kịch bản bash là có thể

Tôi đã phát triển một kịch bản dựa trên các câu trả lời trong Stack Overflow. Một trong những câu trả lời đó đã dẫn đến việc so sánh số phiên bản bằng văn bản của Nhân viên Dell trong năm 2004 cho ứng dụng DKMS.

Mật mã

Tập lệnh bash bên dưới cần được đánh dấu là có thể thực thi được bằng cách sử dụng lệnh chmod a+x script-name. Tôi đang sử dụng tên /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
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.