Как сравнить версию программы в скрипте оболочки?

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 Ничего не происходит
Абхиманью Сахара
1
Есть также вопрос переполнения стека с кучей различных предложений для сравнения строк версий.
n.st
1
Намного проще, чем с помощью труб:gcc -dumpversion
Виктор Ламойн

Ответы:

21

Я не знаю, красиво ли это, но это работает для всех версий формата, которые я знаю.

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

( Примечание: лучшая версия от пользователя 'wildcard': https://unix.stackexchange.com/users/135943/wildcard , удалено дополнительное условие)

Лучано Андресс Мартини
источник
3
Сначала я думал, что это ужасно, а потом понял, что красота сценариев оболочки заключается именно в злоупотреблении такими инструментами. +1
бойкот SE для Моники Челлио
2
Это прерывается, если в операторе печати есть знаки «%». Лучше заменить printf "$requiredver\n$currentver"на printf '%s\n' "$requiredver" "$currentver".
phk
1
-Vявляется расширением GNU, sort(1)таким образом, это решение непереносимо.
Stefanct
1
sort -nработает почти так же, как в случае цифровых версий.
Rockallite
1
@LucianoAndressMartini, посмотрите, что вы думаете о моем редактировании.
Wildcard
2

Здесь я даю решение для сравнения версий ядра Unix. И это должно работать для других, таких как gcc. Я забочусь только о первых двух номерах версии, но вы можете добавить еще один слой логики. Это один лайнер, и я написал его в несколько строк для понимания.

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-подобными? (Моего решения нет)
Лучано Андресс Мартини
1

Раньше мы много проверяли версии в make-файле GNU. Мы выложились через средства 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

источник
Ницца! Это работает и очень легко расширить, и очень портативный!
Брэд Паркс
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 говорит «Восстановить Монику»
Я обычно предпочитаю редактировать существующие ответы, но удалить половину из них сложно: другие могут увидеть ценность там, где я этого не делаю. То же самое для подробных объяснений. Меньше - больше.
МАРТ
Я знаю, что printfповторяет строку формата, но я (отсутствие!) Синтаксис для этого IMHO неясен; поэтому я использую это только когда требуется = когда количество аргументов велико или переменно.
МАРТ
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

Xaqron
источник