Как получить номер версии Bash
Я пишу сценарий, который требует номер версии Bash в простом коротком формате.
Я знаю о bash --version
, но это дает длинный вывод:
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.
Это может быть сокращено до части, которую я хочу, 4.2.10
, этим:
bash --version | grep "bash" | cut -f 4 -d " " | cut -d "-" -f 1 | cut -d "(" -f 1
Тем не менее, такое чувство, что это может привести к поломке, если это сообщение хоть немного изменилось по какой-либо причине.
Есть ли лучший способ сделать это, и что это лучше?
Ответы
Ответ 1
Если вы работаете в оболочке bash, тогда должна быть установлена переменная среды $BASH_VERSION
:
$ echo $BASH_VERSION
4.2.8(1)-release
Это должно быть проще и надежнее для анализа. См. справочную страницу для списка переменных среды, заданных оболочкой.
Ответ 2
Также имеется специальный массив (BASH_VERSINFO), содержащий каждый номер версии в отдельных элементах.
if ((BASH_VERSINFO[0] < 3))
then
echo "Sorry, you need at least bash-3.0 to run this script."
exit 1
fi
Подробнее см. http://www.tldp.org/LDP/abs/html/internalvariables.html:
# Bash version info:
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).
Ответ 3
Чтобы извлечь первую часть:
$ echo ${BASH_VERSION%%[^0-9.]*}
4.2.10
Ответ 4
Кажется, для этого есть переменная среды:
echo $BASH_VERSION
дает
4.1.7(1)-release
на моей машине.
Ответ 5
запустить bash --version
, тогда его вывод понравится
GNU bash, version 3.2.25(1)-release (x86_64-redhat-linux-gnu)
или
GNU bash, version 4.1.2(1)-release (x86_64-redhat-linux-gnu)
или
GNU bash, version 4.3.30(1)-release (x86_64-pc-linux-gnu)
используйте bash переменную $BASH_VERSION
, запустите echo $BASH_VERSION
, ее выход понравится
4.3.30(1)-release
Обычно я использую команду sed
для извлечения версии no, следуя конкретной команде:
bash --version | sed -r -n '[email protected]*version (.*)\(1\)-release.*@\[email protected]'
например:
[[email protected] ~]$ bash --version | sed -r -n '[email protected]*version (.*)\(1\)-release.*@\[email protected]'
4.2.46
[[email protected] ~]$
echo $BASH_VERSION | sed -r -n '[email protected](.*)\(1\)-release.*@\[email protected]'
например:
[[email protected] ~]$ echo $BASH_VERSION | sed -r -n '[email protected](.*)\(1\)-release.*@\[email protected]'
4.2.46
[[email protected] ~]$
Ответ 6
На основе полезного ответа bluecat:
Чтобы сообщить о первых трех компонентах номера версии - например, 4.2.10
- через встроенная переменная оболочки массива BASH_VERSINFO
:
$ bash -c 'IFS=.; echo "${BASH_VERSINFO[*]: 0:3}"'
4.2.10
Если вы вызываете это изнутри Bash script, используйте подоболочку, чтобы локализовать эффект изменения IFS
:
#!/usr/bin/env bash
ver=$(IFS=.; echo "${BASH_VERSINFO[*]: 0:3}") # -> e.g., $ver == '4.2.10'
Объяснение:
-
IFS=.
устанавливает внутренний разделитель полей на .
, что гарантирует, что при печати массива внутри строки с двойными кавычками элементы массива соединяются с этим разделителем.
- Обратите внимание, что вы не можете просто сделать
IFS=. echo ...
для временного переопределения IFS, привязанного к команде echo
, потому что shell расширение параметра (расширение ${BASH_VERSINFO[*]: 0:3}
, в этом случае) происходит до вызова echo
. Поэтому необходимы две отдельные команды; использование подстановка команды ($(...)
) гарантирует, что изменение на IFS
все еще локализовано, потому что подстановки команд выполняются в подоболочках.
-
${BASH_VERSINFO[*]: 0:3}
извлекает первые 3 элемента из переменной массива $BASH_VERSINFO
(начиная с индекса 0
, возвращать 3
элементы).
- Обратите внимание, что для того, чтобы
IFS
работал по назначению, для ссылки на массив должен использоваться *
, а не @
; @
будет неизменно разделять элементы с одним пространством каждый, независимо от значения $IFS
.
Ответ 7
Основываясь больше на отличном ответе Bluecat, вот функция, которая проверяет только основную версию или комбинацию основных и вспомогательных версий и возвращает 0, если текущая версия bash> = требуемая версия:
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
}
Это может быть вызвано как:
check_bash_version 4 # check if 4.0 or above
check_bash_version 4 2 # check if 4.2 or above