วิธีเปรียบเทียบเวอร์ชันของโปรแกรมในเชลล์สคริปต์


14

สมมติว่าฉันต้องการเปรียบเทียบgccรุ่นเพื่อดูว่าระบบได้ติดตั้งรุ่นขั้นต่ำหรือไม่

ในการตรวจสอบgccเวอร์ชั่นฉันดำเนินการดังต่อไปนี้

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

ผลลัพธ์ก็คือ

4.8.5

ดังนั้นฉันจึงเขียนifคำสั่งง่ายๆเพื่อตรวจสอบรุ่นนี้เทียบกับค่าอื่น ๆ

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

แต่มันเกิดข้อผิดพลาด:

[: integer expression expected: 4.8.5

ฉันเข้าใจความผิดพลาดของฉันว่าฉันกำลังใช้สตริงเพื่อเปรียบเทียบและ-ltต้องการจำนวนเต็ม ดังนั้นมีวิธีอื่นในการเปรียบเทียบรุ่นหรือไม่


@ 123 ไม่มีอะไรเกิดขึ้น
Abhimanyu Saharan

1
นอกจากนี้ยังมีคำถาม Stack Overflowพร้อมข้อเสนอแนะมากมายสำหรับการเปรียบเทียบสตริงรุ่น
n.st

1
ง่ายกว่าการใช้ท่อ:gcc -dumpversion
Victor Lamoine

คำตอบ:


22

ฉันไม่รู้ว่ามันสวยงามหรือเปล่า แต่มันใช้ได้กับทุกฟอร์แมตเวอร์ชันที่ฉันรู้จัก

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

( หมายเหตุ:รุ่นที่ดีขึ้นโดยผู้ใช้ 'ตัวแทน': https://unix.stackexchange.com/users/135943/wildcardลบเงื่อนไขเพิ่มเติม)


3
ตอนแรกฉันคิดว่ามันแย่มากแล้วฉันก็ตระหนักว่าความงามของการเขียนสคริปต์เชลล์นั้นแม่นยำในการใช้เครื่องมือในทางที่ผิดเช่นนี้ +1
Boycott SE สำหรับ Monica Cellio

2
สิ่งนี้จะหยุดพักหากมีสัญญาณ '%' ในคำสั่งพิมพ์ ดีกว่าแทนที่ด้วยprintf "$requiredver\n$currentver" printf '%s\n' "$requiredver" "$currentver"
phk

1
-Vเป็นส่วนขยายของ GNU sort(1)ดังนั้นโซลูชันนี้จึงไม่สามารถพกพาได้
stefanct

1
sort -nใช้งานได้เหมือนกันในกรณีที่เป็นตัวเลข
Rockallite

1
@LucianoAndressMartini ดูว่าคุณคิดอย่างไรกับการแก้ไขของฉัน
สัญลักษณ์แทน

2

ที่นี่ฉันให้ทางออกสำหรับการเปรียบเทียบรุ่น Unix Kernel และควรทำงานให้กับผู้อื่นเช่น gcc ฉันสนใจหมายเลขรุ่น 2 แรกเท่านั้น แต่คุณสามารถเพิ่มตรรกะอีกชั้นได้ มันเป็นหนึ่งซับและฉันเขียนมันในหลายบรรทัดเพื่อความเข้าใจ

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
}

คุณสามารถแก้ไขได้และใช้สำหรับการตรวจสอบเวอร์ชั่น gcc


+1 มันเข้ากันได้กับ Unix เหมือนคนอื่น ๆ ? (โซลูชันของฉันไม่ใช่)
Luciano Andress Martini

1

เราเคยตรวจสอบเวอร์ชั่นเป็นจำนวนมากใน GNU makefile เราปอกเปลือกผ่านสิ่งอำนวยความสะดวก makefile เราต้องตรวจสอบ Binutils เก่าและรถรวบรวมคอมไพเลอร์และแก้ไขปัญหาได้ทันที

รูปแบบที่เราใช้คือ:

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

ดี! มันใช้งานได้ดีและง่ายต่อการต่อขยาย
Brad Parks

1

รุ่นที่สั้นกว่า:

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) นี่คือรูปแบบย่อยของคำตอบที่ได้รับแล้ว คุณสามารถเพิ่มมูลค่าด้วยการเพิ่มคำอธิบายซึ่งยังไม่ได้โพสต์ (2)  printf '%s\n'ดีพอ printfจะทำซ้ำสตริงรูปแบบตามต้องการ
G-Man กล่าวว่า 'Reinstate Monica'

ปกติแล้วฉันชอบแก้ไขคำตอบที่มีอยู่แล้ว แต่การลบครึ่งหนึ่งนั้นเป็นเรื่องยุ่งยาก: คนอื่น ๆ อาจเห็นคุณค่าที่ฉันไม่ชอบ เช่นเดียวกับคำอธิบายอย่างละเอียด น้อยกว่ามาก
MarcH

ฉันรู้ว่าprintfซ้ำสตริงรูปแบบ แต่ฉัน (ขาด!) ​​ไวยากรณ์สำหรับนี้ IMHO ชัดเจน; ดังนั้นฉันจึงใช้สิ่งนี้เฉพาะเมื่อต้องการ = เมื่อจำนวนอาร์กิวเมนต์มีมากหรือแปรปรวน
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: <

เครดิตไปที่@Shellman

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