3

I want to get the version of glibc and use it in an if statement stating if glibc is less than 2.15 then.

However the issue is that when using the ldd --version this is output as a string. i need to convert it in to an integer to do the less than comparison.

Previously I have done it this way

if [ "$(ldd --version | sed -n '1 p' | tr -cd '[:digit:]' | tail -c 3)" -lt 215 ]; then

This is not really very good as I have to remove the decimal point and cannot give a true version number comparison. The other issue is that some versions of glibc have multiple decimal points (seen here https://en.wikipedia.org/wiki/GNU_C_Library#Version_history) which would mean my existing comparison would mess up.

So to that end I would need to be able to convert the glibc version intact to an integer and correctly compare the version numbers even with multiple decimal points.

Any ideas? Thanks

  • Are you sure you "need to convert it to an integer"? It sounds like floating point comparison would suit your purposes better; is that the case? – Wildcard Mar 11 '16 at 23:18
  • Why do you want to do this in bash and not use a tool that's been designed for this kind of job, e.g. perl's sort::version ? Also, read glibc faq to learn how to get just the version number (no ugly parsing needed). – don_crissti Mar 11 '16 at 23:47
2
ldd --version | sed 's/.* //;q' | awk -F. '{ if ($1 > 2 || ($1 == 2 && $2 >= 15)) { exit 0 } else {exit 1} }'

Explanation:

The sed command takes the first line of output from ldd --version, strips out everything up to and including the last space, and then quits (so it only prints the number).

The -F flag to awk sets . as the field separator.

If the first number (before the dot) is greater than 2, or if the first number is 2 and the second number is at least 15, the awk exit status will be "true". Otherwise, it will be false.

You can use this in a bash script like so:

if ldd --version | sed 's/.* //;q' | awk -F. '{ if ($1 > 2 || ($1 == 2 && $2 >= 15)) { exit 0 } else {exit 1} }' ; then
  echo "Version is 2.15 or later"
else
  echo "Version is too old."
fi
  • awk can do floating point comparisons. Also sed isn't required because awk has a function called gsub() that can do regexp transformations on any "variable" (including $0). e.g. ldd --version | awk '{if (NR==1) { gsub(/.* /,"",$0) ; if ($0 >= 2.15) { exit 0 } else {exit 1} }}'. or even ldd --version | awk '{if (NR==1) { gsub(/.* /,"",$0) ; exit ($0 < 2.15)}}' – cas Mar 12 '16 at 2:18
  • @cas, the OP mentioned there may be more than one decimal point, e.g. "2.7.3". – Wildcard Mar 12 '16 at 2:38
  • That is true it needs to compare up to 3 decimal places as its a version number. On a side note sorting of version numbers with 3 decimal places was done with the sort command sort -r --version-sort -o versions.txt – dgibbs Mar 12 '16 at 11:55
  • in that case, modify the gsub() function call to also remove the second and subsequent decimal points - 2.7.3 is still smaller than 2.15 and you only need to compare 2.7 against 2.15 to find that out. – cas Mar 13 '16 at 0:16
1

Don't convert the version string to an integer. Compare the strings.

This is a bit overkill for your use case, but here's a shell function that compares typical version strings. It follows a subset of the Debian version comparison rules:

  • The versions are compared chunk by chunk. Each chunk consists of a maximal sequence of characters that either entirely consists of digits or contains no digits.
  • Non-digit sequences are compared in lexicographic order.
  • Digit sequences are compared according to decimal value. In particular, leading zeros are irrelevant.

Note that last point: 1.01 is considered equal to 1.1. This is the price to pay for 1.1 and 1.9 to be considered less than 1.10.

This code requires dash, bash, ksh or zsh. To use it with other shells such as BusyBox sh, replace calls to [ "STRING1" \> "STRING2" ] by expr "aSTRING1" \> "aSTRING2".

version_ge () (
  version1="$1" version2="$2"
  while true; do
    prefix1="${version1%%[0-9]*}" prefix2="${version2%%[0-9]*}"
    if [ "$prefix1" \> "$prefix2" ]; then return 0; fi
    if [ "$prefix2" \> "$prefix1" ]; then return 1; fi
    version1="${version1#"$prefix1"}" version2="${version2#"$prefix2"}"
    prefix1="${version1%%[!0-9]*}" prefix2="${version2%%[!0-9]*}"
    version1="${version1#"$prefix1"}" version2="${version2#"$prefix2"}"
    case "$prefix2" in
      0*[!0]*) prefix2="${prefix2##"${prefix2%%[!0]*}"}";;
      *[!0]*) :;;
      *) return 0;;
    esac
    case "$prefix1" in
      0*[!0]*) prefix1="${prefix1##"${prefix1%%[!0]*}"}";;
      *[!0]*) :;;
      *) return 1;;
    esac
    if [ "${#prefix1}" -gt "${#prefix2}" ]; then return 0; fi
    if [ "${#prefix1}" -lt "${#prefix2}" ]; then return 1; fi
    if [ "$prefix1" \> "$prefix2" ]; then return 0; fi
    if [ "$prefix2" \> "$prefix1" ]; then return 1; fi
  done
)
1

sort can sort version numbers; taking advange of that you could write something like this:

if [ $(printf '%s\n2.15\n' $(ldd --version | sed -n '1s/.* //p') | sort -V | head -n 1) != 2.15 ]; then
    # ...
fi

printf '%s\n2.15\n' $(ldd --version | sed -n '1s/.* //p') prints ldd's version number and 2.15 on two separate lines, sort -V sorts them in ascending order and head -n 1 prints the first line; the outer command substitution is replaced with the output and the output is compared to 2.15; if the output is not 2.15, the if body is executed.

Sample output on my machine with ldd 2.21:

% [ $(printf '%s\n2.15\n' $(ldd --version | sed -n '1s/.* //p') | sort -V | head -n 1) != 2.15 ] && printf 'Version %s is lower than 2.15\n' $(ldd --version | sed -n '1s/.* //p') || printf 'Version %s is equal or higher than 2.15\n' $(ldd --version | sed -n '1s/.* //p')
Version 2.21 is equal or higher than 2.15

Sample output on some hard-coded values, just to demonstrate the method deals with the complexity of version sorting:

% glibc_version=2.15
% [ $(printf '%s\n2.15\n' $glibc_version | sort -V | head -n 1) != 2.15 ] && printf 'Version %s is lower than 2.15\n' $glibc_version || printf 'Version %s is equal or higher than 2.15\n' $glibc_version
Version 2.15 is equal or higher than 2.15
% glibc_version=2.16  
% [ $(printf '%s\n2.15\n' $glibc_version | sort -V | head -n 1) != 2.15 ] && printf 'Version %s is lower than 2.15\n' $glibc_version || printf 'Version %s is equal or higher than 2.15\n' $glibc_version
Version 2.16 is equal or higher than 2.15
% glibc_version=2.15.1
[ $(printf '%s\n2.15\n' $glibc_version | sort -V | head -n 1) != 2.15 ] && printf 'Version %s is lower than 2.15\n' $glibc_version || printf 'Version %s is equal or higher than 2.15\n' $glibc_version
Version 2.15.1 is equal or higher than 2.15
% glibc_version=2.14
% [ $(printf '%s\n2.15\n' $glibc_version | sort -V | head -n 1) != 2.15 ] && printf 'Version %s is lower than 2.15\n' $glibc_version || printf 'Version %s is equal or higher than 2.15\n' $glibc_version
Version 2.14 is lower than 2.15
  • Looks good I will try it out :D – dgibbs Mar 12 '16 at 12:42

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.