Bagaimana cara membandingkan versi program dalam skrip shell?

14

Misalkan saya ingin membandingkan gcc versi untuk melihat apakah sistem memiliki versi minimum yang diinstal atau tidak.

Untuk memeriksa gccversinya, saya menjalankan yang berikut ini

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

Outputnya adalah

4.8.5

Jadi, saya menulis ifpernyataan sederhana untuk memeriksa versi ini terhadap beberapa nilai lainnya

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

Tapi itu melempar kesalahan:

[: integer expression expected: 4.8.5

Saya mengerti kesalahan saya bahwa saya menggunakan string untuk membandingkan dan -ltmembutuhkan integer. Jadi, apakah ada cara lain untuk membandingkan versi?

Abimanyu Saharan
sumber
@ 123 Tidak ada yang terjadi
Abimanyu Saharan
1
Ada juga pertanyaan Stack Overflow dengan banyak saran berbeda untuk membandingkan string versi.
n.st
1
Jauh lebih sederhana daripada menggunakan pipa:gcc -dumpversion
Victor Lamoine

Jawaban:

21

Saya tidak tahu apakah itu indah, tetapi berfungsi untuk setiap format versi yang saya tahu.

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

( Catatan: versi yang lebih baik oleh pengguna 'wildcard': https://unix.stackexchange.com/users/135943/wildcard , menghapus ketentuan tambahan)

Luciano Andress Martini
sumber
3
Pada awalnya saya pikir ini mengerikan, dan kemudian saya menyadari keindahan skrip shell tepatnya dalam alat yang menyalahgunakan seperti ini. +1
Boikot SE untuk Monica Cellio
2
Ini rusak jika ada tanda '%' dalam pernyataan cetak. Lebih baik ganti printf "$requiredver\n$currentver"dengan printf '%s\n' "$requiredver" "$currentver".
phk
1
-Vadalah perpanjangan GNU sort(1)sehingga solusi ini non-portabel.
stefanct
1
sort -nbekerja hampir sama dengan cara dalam kasus versi angka.
Rockallite
1
@LucianoAndressMartini, lihat pendapat Anda tentang edit saya.
Wildcard
2

Di sini saya memberikan solusi untuk membandingkan versi Unix Kernel. Dan itu harus bekerja untuk orang lain seperti gcc. Saya hanya peduli untuk nomor versi 2 pertama tetapi Anda dapat menambahkan lapisan logika lain. Ini adalah satu liner dan saya menulisnya dalam beberapa baris untuk memahami.

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
}

Anda dapat memodifikasi ini dan menggunakannya untuk memeriksa versi gcc.

Kemin Zhou
sumber
+1 ini kompatibel dengan Unix-like lainnya? (Solusi saya bukan)
Luciano Andress Martini
1

Kami biasa melakukan banyak pemeriksaan versi di makefile GNU. Kami keluar melalui fasilitas makefile. Kami harus mendeteksi Binutils lama dan kompiler buggy dan menyelesaikannya dengan cepat.

Pola yang kami gunakan adalah:

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

sumber
Bagus! Ini berfungsi dan sangat mudah diperluas, dan sangat portabel!
Brad Parks
1

Versi lebih pendek:

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"
Maret
sumber
(1) Ini adalah variasi kecil dari jawaban yang sudah diberikan. Anda dapat menambah nilai dengan menambahkan penjelasan, yang belum diposting. (2)  printf '%s\n'cukup baik; printfakan mengulangi format string sesuai kebutuhan.
G-Man Mengatakan 'Reinstate Monica'
Saya biasanya lebih suka mengedit jawaban yang sudah ada tetapi menghapusnya setengah dari itu rumit: orang lain mungkin melihat nilai di mana saya tidak. Sama untuk penjelasan verbose. Kurang itu lebih.
MarcH
Saya tahu bahwa printfmengulangi format string tetapi saya sintaks (kurangnya!) Untuk ini adalah IMHO jelas; jadi saya menggunakan ini hanya bila diperlukan = ketika jumlah argumen besar atau variabel.
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: <

Kredit jatuh ke @Shellman

Xaqron
sumber