Для версий 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-}для получения пустой строки, когда значение foobarundefined и значение foobarиначе (или поставить любое другое значение по умолчанию после -).
В ksh, если foobarобъявлен, но не определен, как в typeset -a foobar, то ${foobar+1}расширяется до пустой строки.
Zsh не имеет переменных, которые объявлены, но не установлены: typeset -a foobarсоздает пустой массив.
В bash массивы ведут себя по-другому и удивительно. ${a+1}расширяется только до 1if, если 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, а оператор для условных выражений.