Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems. It's 100% free, no registration required.

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

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

share|improve this question
    
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 3 hours ago
    
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 2 hours ago
up vote 2 down vote accepted
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
share|improve this answer
    
Thanks this does exactly the sort of thing im after :-D – dgibbs 2 hours ago
    
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 12 mins ago

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
)
share|improve this answer

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
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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