Для версий Bash до "GNU bash, Версия 4.2" есть ли эквивалентные альтернативы -v
опции test
команды? Например:
shopt -os nounset
test -v foobar && echo foo || echo bar
# Output: bar
foobar=
test -v foobar && echo foo || echo bar
# Output: foo
Для версий Bash до "GNU bash, Версия 4.2" есть ли эквивалентные альтернативы -v
опции test
команды? Например:
shopt -os nounset
test -v foobar && echo foo || echo bar
# Output: bar
foobar=
test -v foobar && echo foo || echo bar
# Output: foo
Ответы:
Переносим на все оболочки POSIX:
if [ -n "${foobar+1}" ]; then
echo "foobar is defined"
else
echo "foobar is not defined"
fi
Сделайте это, ${foobar:+1}
если вы хотите обрабатывать foobar
одинаково, независимо от того, пусто оно или не определено. Вы также можете использовать ${foobar-}
для получения пустой строки, когда значение foobar
undefined и значение foobar
иначе (или поставить любое другое значение по умолчанию после -
).
В ksh, если foobar
объявлен, но не определен, как в typeset -a foobar
, то ${foobar+1}
расширяется до пустой строки.
Zsh не имеет переменных, которые объявлены, но не установлены: typeset -a foobar
создает пустой массив.
В bash массивы ведут себя по-другому и удивительно. ${a+1}
расширяется только до 1
if, если a
это не пустой массив, например
typeset -a a; echo ${a+1} # prints nothing
e=(); echo ${e+1} # prints nothing!
f=(''); echo ${f+1} # prints 1
Тот же принцип применяется к ассоциативным массивам: переменные массива обрабатываются как определенные, если они имеют непустой набор индексов.
Другой, специфичный для bash способ проверки того, была ли определена переменная любого типа, состоит в проверке того, находится ли она в списке . Это сообщает о пустых массивах, как определено, в отличие от , но сообщает объявленные, но неназначенные переменные ( ) как неопределенные.${!PREFIX*}
${foobar+1}
unset foobar; typeset -a foobar
case " ${!foobar*} " in
*" foobar "*) echo "foobar is defined";;
*) echo "foobar is not defined";;
esac
Это эквивалентно проверке возвращаемого значения typeset -p foobar
илиdeclare -p foobar
, за исключением того, что происходит typeset -p foobar
сбой на объявленных, но неназначенных переменных.
В bash, как и в ksh, set -o nounset; typeset -a foobar; echo $foobar
выдает ошибку при попытке раскрыть неопределенную переменную foobar
. В отличие от ksh, set -o nounset; foobar=(); echo $foobar
(или echo "${foobar[@]}"
) также вызывает ошибку.
Обратите внимание, что во всех описанных здесь ситуациях, ${foobar+1}
расширяется до пустой строки тогда и только тогда, $foobar
когда вызовет ошибку в set -o nounset
.
echo "${foobar:+1}"
не печатает, 1
если он declare -a foobar
был выпущен ранее, и поэтому foobar
является индексированным массивом. declare -p foobar
правильно сообщает declare -a foobar='()'
. Работает "${foobar:+1}"
только для переменных, не являющихся массивами?
${foobar+1}
(без :
, я перевернул два примера в своем первоначальном ответе) правильно для массивов в bash, если ваше определение «определено» - «будет $foobar
работать под set -o nounset
». Если ваше определение отличается, bash немного странный. Смотрите мой обновленный ответ.
0
индекс, ни ключ не определены так, как это верно a=()
, то ${a+1}
ничего не возвращает правильно.
defined
оператор. Test
мог сделать это; это не может быть сложно ( гм ....)
Подводя итог ответу Жиля, я сформулировал следующие правила:
[[ -v foobar ]]
для переменных в версии Bash> = 4.2.declare -p foobar &>/dev/null
для переменных массива в версии Bash <4.2.(( ${foo[0]+1} ))
или (( ${bar[foo]+1} ))
для индексов массивов indexed ( -a
) и keyed ( -A
) declare
соответственно. Варианты 1 и 2 здесь не работают.Я использую одну и ту же технику для всех переменных в bash, и она работает, например:
[ ${foobar} ] && echo "foobar is set" || echo "foobar is unset"
выходы:
foobar is unset
в то время как
foobar=( "val" "val2" )
[ ${foobar} ] && echo "foobar is set" || echo "foobar is unset"
выходы:
foobar is set
foobar=""
потом сообщу об этом foobar is unset
. Нет, подожди, я заберу это обратно. Действительно только проверяет, является ли первый элемент пустым или нет, так что будет хорошей идеей, если вы знаете, что переменная НЕ является массивом, и вам нужна только пустота, а не определенность.
-v
не вариантtest
, а оператор для условных выражений.