Reputation: 1808
I'm writing a script which requires the Bash version number in a simple short format.
I'm aware of bash --version
, but this gives a long output:
GNU bash, version 4.2.10(1)-release (i686-pc-linux-gnu)
Copyright (C) 2011 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
This could be cut down to the bit I want, 4.2.10
, by this:
bash --version | grep "bash" | cut -f 4 -d " " | cut -d "-" -f 1 | cut -d "(" -f 1
However, this feels like it would be prone to break if that message ever changed slightly for whatever reason.
Is there a better way to do this, and what is this better way?
Upvotes: 39
Views: 27175
Reputation: 6228
This is a variation of other responses with BASH_VERSINFO
:
check_bash_version()
{
local a=4 b=3 # Bash version >= a.b
(( BASH_VERSINFO[0] > a || \
(BASH_VERSINFO[0] == a && BASH_VERSINFO[1] >= b) )) || {
echo "Error: Bash version >= $a.$b expected." >&2
return 1
}
}
check_bash_version || exit 1
Upvotes: 0
Reputation: 42999
Building more on FelixEnescu's great answer, here is a function that checks for just the major version or a combination of major and minor versions and returns 0 if the current Bash version is >= the needed version:
check_bash_version() {
local major=${1:-4}
local minor=$2
local rc=0
local num_re='^[0-9]+$'
if [[ ! $major =~ $num_re ]] || [[ $minor && ! $minor =~ $num_re ]]; then
printf '%s\n' "ERROR: version numbers should be numeric"
return 1
fi
if [[ $minor ]]; then
local bv=${BASH_VERSINFO[0]}${BASH_VERSINFO[1]}
local vstring=$major.$minor
local vnum=$major$minor
else
local bv=${BASH_VERSINFO[0]}
local vstring=$major
local vnum=$major
fi
((bv < vnum)) && {
printf '%s\n' "ERROR: Need Bash version $vstring or above, your version is ${BASH_VERSINFO[0]}.${BASH_VERSINFO[1]}"
rc=1
}
return $rc
}
It can be invoked as:
check_bash_version 4 # Check if 4.0 or above
check_bash_version 4 2 # Check if 4.2 or above
See the assertion related to this:
Upvotes: 2
Reputation:
Run bash --version
and then its output is like:
GNU bash, version 3.2.25(1)-release (x86_64-redhat-linux-gnu)
or
GNU bash, version 4.1.2(1)-release (x86_64-redhat-linux-gnu)
or
GNU bash, version 4.3.30(1)-release (x86_64-pc-linux-gnu)
Use Bash variable $BASH_VERSION
and run echo $BASH_VERSION
. Its output is like:
4.3.30(1)-release
Usually I use command sed
to extract the version number, the following is the concrete command:
bash --version | sed -r -n 's@.*version (.*)\(1\)-release.*@\1@p'
For example:
[flying@lempstacker ~]$ bash --version | sed -r -n 's@.*version (.*)\(1\)-release.*@\1@p'
4.2.46
[flying@lempstacker ~]$
echo $BASH_VERSION | sed -r -n 's@(.*)\(1\)-release.*@\1@p'
For example:
[flying@lempstacker ~]$ echo $BASH_VERSION | sed -r -n 's@(.*)\(1\)-release.*@\1@p'
4.2.46
[flying@lempstacker ~]$
Upvotes: 1
Reputation: 5102
There's also a special array (BASH_VERSINFO) containing each version number in separate elements.
if ((BASH_VERSINFO[0] < 3))
then
echo "Sorry, you need at least bash-3.0 to run this script."
exit 1
fi
See 9.1. Internal Variables for more information:
# Bash version information:
for n in 0 1 2 3 4 5
do
echo "BASH_VERSINFO[$n] = ${BASH_VERSINFO[$n]}"
done
# BASH_VERSINFO[0] = 3 # Major version no.
# BASH_VERSINFO[1] = 00 # Minor version no.
# BASH_VERSINFO[2] = 14 # Patch level.
# BASH_VERSINFO[3] = 1 # Build version.
# BASH_VERSINFO[4] = release # Release status.
# BASH_VERSINFO[5] = i386-redhat-linux-gnu # Architecture
# (same as $MACHTYPE).
Upvotes: 44
Reputation: 21663
If you're running within a Bash shell, then the $BASH_VERSION
environment variable should be set:
$ echo $BASH_VERSION
4.2.8(1)-release
That should be easier and more reliable to parse. See the man page for a list of environment variables set by the shell.
Upvotes: 37
Reputation: 438083
Building on FelixEnescu's helpful answer:
To report the first 3 version-number components - e.g., 4.2.10
- via built-in array shell variable BASH_VERSINFO
:
$ bash -c 'IFS=.; echo "${BASH_VERSINFO[*]: 0:3}"'
4.2.10
If you're calling this from inside a Bash script, use a subshell in order to localize the effect of changing IFS
:
#!/usr/bin/env bash
ver=$(IFS=.; echo "${BASH_VERSINFO[*]: 0:3}") # -> e.g., $ver == '4.2.10'
Explanation:
IFS=.
sets the internal field separator to .
, which ensures that when we print an array inside a double-quoted string later, the array's elements are joined with that separator.
IFS=. echo ...
to transiently redefine IFS scoped to the the echo
command, because shell parameter expansion (the expansion of ${BASH_VERSINFO[*]: 0:3}
, in this case) happens before echo
is invoked. Therefore, two separate command are needed; the use of a command substitution ($(...)
) ensures that the change to IFS
is still localized, because command substitutions run in subshells.${BASH_VERSINFO[*]: 0:3}
extracts the first 3 elements from array variable $BASH_VERSINFO
(starting at index 0
, return 3
elements).
IFS
to work as intended, *
rather than @
must be used to reference the array; @
would invariably separate the elements with a single space each, irrespective of the value of $IFS
.Upvotes: 2
Reputation: 69977
There seems to be an environment variable for this:
echo $BASH_VERSION
yields
4.1.7(1)-release
on my machine.
Upvotes: 4