Làm cách nào để so sánh phiên bản của chương trình trong tập lệnh shell?


14

Giả sử tôi muốn so sánh gccphiên bản để xem hệ thống có cài đặt phiên bản tối thiểu hay không.

Để kiểm tra gccphiên bản, tôi đã thực hiện như sau

gcc --version | head -n1 | cut -d" " -f4

Đầu ra là

4.8.5

Vì vậy, tôi đã viết một iftuyên bố đơn giản để kiểm tra phiên bản này với một số giá trị khác

if [ "$(gcc --version | head -n1 | cut -d" " -f4)" -lt 5.0.0 ]; then
    echo "Less than 5.0.0"
else
    echo "Greater than 5.0.0"
fi

Nhưng nó ném một lỗi:

[: integer expression expected: 4.8.5

Tôi hiểu sai lầm của mình rằng tôi đã sử dụng các chuỗi để so sánh và -ltyêu cầu số nguyên. Vì vậy, có cách nào khác để so sánh các phiên bản?


@ 123 Không có gì xảy ra
Abhimanyu Sahara

1
Ngoài ra còn có một câu hỏi Stack Overflow với một loạt các đề xuất khác nhau để so sánh các chuỗi phiên bản.
n.st

1
Đơn giản hơn nhiều so với sử dụng đường ống:gcc -dumpversion
Victor Lamoine

Câu trả lời:


21

Tôi không biết nó có đẹp không, nhưng nó hoạt động với mọi định dạng phiên bản mà tôi biết.

#!/bin/bash
currentver="$(gcc -dumpversion)"
requiredver="5.0.0"
 if [ "$(printf '%s\n' "$requiredver" "$currentver" | sort -V | head -n1)" = "$requiredver" ]; then 
        echo "Greater than or equal to 5.0.0"
 else
        echo "Less than 5.0.0"
 fi

( Lưu ý: phiên bản tốt hơn của người dùng 'ký tự đại diện': https://unix.stackexchange.com/users/135943/wildcard , đã xóa điều kiện bổ sung)


3
Lúc đầu, tôi nghĩ điều này thật tồi tệ, và sau đó tôi nhận ra vẻ đẹp của kịch bản shell là chính xác trong việc lạm dụng các công cụ như thế này. +1
Tẩy chay SE cho Monica Cellio

2
Điều này sẽ phá vỡ nếu có dấu '%' trong câu lệnh in. Thay thế tốt hơn printf "$requiredver\n$currentver"bằng printf '%s\n' "$requiredver" "$currentver".
phk

1
-Vlà một phần mở rộng GNU sort(1)do đó giải pháp này không khả dụng.
stefanct

1
sort -nhoạt động khá giống nhau trong trường hợp phiên bản số.
Rockallite

1
@LucianoAndressMartini, hãy xem bạn nghĩ gì về chỉnh sửa của tôi.
tự đại diện

2

Ở đây tôi đưa ra một giải pháp để so sánh các phiên bản Unix Kernel. Và nó nên làm việc cho những người khác như gcc. Tôi chỉ quan tâm đến số phiên bản 2 đầu tiên nhưng bạn có thể thêm một lớp logic khác. Nó là một lớp lót và tôi đã viết nó thành nhiều dòng để hiểu.

check_linux_version() {
    version_good=$(uname -r | awk 'BEGIN{ FS="."}; 
    { if ($1 < 4) { print "N"; } 
      else if ($1 == 4) { 
          if ($2 < 4) { print "N"; } 
          else { print "Y"; } 
      } 
      else { print "Y"; }
    }')

    #if [ "$current" \< "$expected" ]; then
    if [ "$version_good" = "N" ]; then
        current=$(uname -r)
        echo current linux version too low
        echo current Linux: $current
        echo required 4.4 minimum
        return 1
    fi
}

Bạn có thể sửa đổi điều này và sử dụng nó để kiểm tra phiên bản gcc.


+1 nó có tương thích với các Unix giống như khác không? (Giải pháp của tôi là không)
Luciano Andress Martini

1

Chúng tôi đã từng thực hiện rất nhiều phiên bản kiểm tra trong tệp Makefile GNU. Chúng tôi lột vỏ thông qua các cơ sở makefile. Chúng tôi đã phải phát hiện Binutils cũ và trình biên dịch lỗi và giải quyết chúng một cách nhanh chóng.

Mẫu chúng tôi sử dụng là:

#!/usr/bin/env bash

CC=$(command -v gcc)
GREP=$(command -v grep)

# Fixup CC and GREP as needed. It may be needed on AIX, BSDs, and Solaris
if [[ -f "/usr/gnu/bin/grep" ]]; then
    GREP="/usr/gnu/bin/grep"
elif [[ -f "/usr/linux/bin/grep" ]]; then
    GREP="/usr/linux/bin/grep"
elif [[ -f "/usr/xpg4/bin/grep" ]]; then
    GREP="/usr/xpg4/bin/grep"
fi

# Check compiler for GCC 4.8 or later
GCC48_OR_LATER=$("$CXX" -v 2>&1 | "$GREP" -i -c -E "gcc version (4\.[8-9]|[5-9]\.)")
if [[ "$GCC48_OR_LATER" -ne 0 ]];
then
   ...
fi

# Check assembler for GAS 2.19 or later
GAS219_OR_LATER=$("$CXX" -xc -c /dev/null -Wa,-v -o/dev/null 2>&1 | "$GREP" -c -E "GNU assembler version (2\.19|2\.[2-9]|[3-9])")
if [[ "$GAS219_OR_LATER" -ne 0 ]];
then
   ...
fi

Đẹp! Điều này hoạt động và siêu dễ dàng để mở rộng, và rất di động!
Brad park

1

Phiên bản ngắn hơn:

version_greater_equal()
{
    printf '%s\n%s\n' "$2" "$1" | sort -V -C
}

version_greater_equal "${gcc_version}" 8.2 || die "need 8.2 or above"

(1) Đây là một biến thể nhỏ của các câu trả lời đã được đưa ra. Bạn có thể thêm giá trị bằng cách thêm một lời giải thích, chưa được đăng. (2)  printf '%s\n'là đủ tốt; printfsẽ lặp lại chuỗi định dạng khi cần thiết.
G-Man nói 'Phục hồi Monica'

Tôi thường thích chỉnh sửa các câu trả lời hiện có nhưng xóa một nửa trong số đó là khó khăn: những người khác có thể thấy giá trị ở nơi tôi không. Tương tự cho giải thích dài dòng. Càng đơn giản càng đẹp.
MarcH

Tôi biết rằng printflặp lại chuỗi định dạng nhưng tôi cú pháp (thiếu!) Cho điều này là tối nghĩa IMHO; vì vậy tôi chỉ sử dụng điều này khi được yêu cầu = khi số lượng đối số lớn hoặc biến.
MarcH

1
function version_compare () {
  function sub_ver () {
    local len=${#1}
    temp=${1%%"."*} && indexOf=`echo ${1%%"."*} | echo ${#temp}`
    echo -e "${1:0:indexOf}"
  }
  function cut_dot () {
    local offset=${#1}
    local length=${#2}
    echo -e "${2:((++offset)):length}"
  }
  if [ -z "$1" ] || [ -z "$2" ]; then
    echo "=" && exit 0
  fi
  local v1=`echo -e "${1}" | tr -d '[[:space:]]'`
  local v2=`echo -e "${2}" | tr -d '[[:space:]]'`
  local v1_sub=`sub_ver $v1`
  local v2_sub=`sub_ver $v2`
  if (( v1_sub > v2_sub )); then
    echo ">"
  elif (( v1_sub < v2_sub )); then
    echo "<"
  else
    version_compare `cut_dot $v1_sub $v1` `cut_dot $v2_sub $v2`
  fi
}

### Usage:

version_compare "1.2.3" "1.2.4"
# Output: <

Tín dụng vào @Shellman

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.