15

Suppose I want to compare gcc version to see whether the system has the minimum version installed or not.

To check the gcc version, I executed the following

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

The output was

4.8.5

So, I wrote a simple if statement to check this version against some other value

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

But it throws an error:

[: integer expression expected: 4.8.5

I understood my mistake that I was using strings to compare and the -lt requires integer. So, is there any other way to compare the versions?

  • @123 Nothing happens – Abhimanyu Saharan May 27 '16 at 14:21
  • 1
    There's also a Stack Overflow question with a bunch of different suggestions for comparing version strings. – n.st May 29 '16 at 3:31
  • 1
    Much simpler than using pipes: gcc -dumpversion – Victor Lamoine Jan 4 '17 at 14:18
27

I don't know if it is beautiful, but it is working for every version format I know.

#!/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 ${requiredver}"
 else
        echo "Less than ${requiredver}"
 fi

(Note: better version by the user 'wildcard': https://unix.stackexchange.com/users/135943/wildcard , removed additional condition)

| improve this answer | |
  • 4
    At first I thought this was awful, and then I realized the beauty of shell scripting is precisely in abusing tools like this. +1 – Xiong Chiamiov May 27 '16 at 23:52
  • 2
    This breaks if there are '%' signs in the print statement. Better replace printf "$requiredver\n$currentver" with printf '%s\n' "$requiredver" "$currentver". – phk Nov 5 '16 at 10:50
  • 1
    -V is a GNU extension of sort(1) thus this solution is non-portable. – stefanct Sep 4 '17 at 0:46
  • 1
    sort -n works pretty much the same way in case of numeral versions. – Rockallite Nov 22 '17 at 7:22
  • 1
    @LucianoAndressMartini, see what you think of my edit. – Wildcard Jan 22 '18 at 23:28
2

Here I give a solution for comparing Unix Kernel versions. And it should work for others such as gcc. I only care for the first 2 version number but you can add another layer of logic. It is one liner and I wrote it in multiple line for understanding.

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
}

You can modify this and use it for gcc version checking.

| improve this answer | |
2

Shorter version:

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"
| improve this answer | |
  • (1) This is a minor variation of already-given answers.  You could add value by adding an explanation, which has not yet been posted.  (2) printf '%s\n' is good enough; printf will repeat the format string as needed. – G-Man Says 'Reinstate Monica' Feb 14 at 8:25
  • I normally prefer editing existing answers but deleting half of them is tricky: others may see value where I don't. Same for verbose explanations. Less is more. – MarcH Feb 18 at 19:56
  • I know that printf repeats the format string but I the (lack of!) syntax for this is IMHO obscure; so I use this only when required = when the number of arguments is large or variable. – MarcH Feb 18 at 19:59
1

We used to do a lot of version checking in a GNU makefile. We shelled out through the makefile facilities. We had to detect old Binutils and buggy compilers and workaround them on the fly.

The pattern we used was:

#!/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
| improve this answer | |
  • Nice! This works and is super easy to extend, and very portable! – Brad Parks Apr 22 at 16:19
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: <

Credit goes to @Shellman

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.