Как протестировать, если переменная определяется вообще в Bash до версии 4.2 с опцией оболочки nounset?

Альтернатива должна передать вывод по каналу и проанализировать его с последующими командами. Единственный безопасный способ сделать так состоит в том, чтобы использовать -print0 опция, которая говорит find использовать нулевой символ в качестве разделителя результатов. Команды получения должны иметь способность распознать, что пустой указатель разграничил вход. Пример:

find /home/phunehehe -iregex '.*\.png$' -print0 | xargs -0 file

Обратите внимание что -0 опция говорит xargs рассматривать вход как разграниченный пустой указатель.

16
27.11.2012, 01:38
3 ответа

Портативный ко всем оболочкам POSIX:

if [ -n "${foobar+1}" ]; then
  echo "foobar is defined"
else
  echo "foobar is not defined"
fi

Сделайте это ${foobar:+1} если Вы хотите рассматривать foobar тот же путь, пусто ли это или не определенное. Можно также использовать ${foobar-} получить пустую строку когда foobar не определено и значение foobar иначе (или помещенный любое другое значение по умолчанию после -).

В ksh, если foobar объявляется, но не определяется, как в typeset -a foobar, затем ${foobar+1} расширяется до пустой строки.

Zsh не имеет переменных, которые объявляются, но не устанавливаются: typeset -a foobar создает пустой массив.

В ударе массивы ведут себя другим и удивительным способом. ${a+1} только расширяется до 1 если a непустой массив, например.

typeset -a a; echo ${a+1}    # prints nothing
e=(); echo ${e+1}            # prints nothing!
f=(''); echo ${f+1}          # prints 1

Тот же принцип относится к ассоциативным массивам: переменные типа массив рассматривают, как определено, если у них есть непустое множество индексов.

Другой, особенный метод удара тестирования, была ли переменная какого-либо типа определена, состоит в том, чтобы проверить, перечислено ли это в ${!PREFIX*}. Это сообщает о пустых массивах, как определено, в отличие от этого, ${foobar+1}, но отчеты declared-unassigned (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 сбои на declared-unassigned.

В ударе, как в 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.

36
27.01.2020, 19:48
  • 1
    Что относительно массивов? В версии Bash "удар GNU, версия 4.1.10 (4) - выпуск (i686-pc-cygwin)" echo "${foobar:+1}" не печатает 1 если declare -a foobar был ранее выпущен и таким образом foobar индексный массив. declare -p foobar правильно отчеты declare -a foobar='()'. Делает "${foobar:+1}" только работа для непеременных типа массив? –  Tim Friske 27.11.2012, 11:29
  • 2
    @TimFriske ${foobar+1} (без :, Я инвертировал два примера в своем исходном ответе), корректно для массивов в ударе, если Ваше определение “определенных”, “был бы $foobar работа под set -o nounset”. Если Ваше определение отличается, удар является немного странным. См. мой обновленный ответ. –  Gilles 'SO- stop being evil' 27.11.2012, 12:56
  • 3
    Относительно темы "В ударе, массивы ведут себя другим и удивительным способом". поведение может быть объяснено от удара (1) страницы справочника, раздел "Arrays". Это указывает, что "Ссылка на переменную типа массив без нижнего индекса эквивалентна ссылке на массив с нижним индексом 0".. Таким образом, если ни один a 0 индекс, ни ключ определяются, поскольку это верно для a=(), ${a+1} правильно возвраты ничто. –  Tim Friske 27.11.2012, 23:57
  • 4
    @TimFriske я знаю, что реализация удара соответствует своей документации. Но обработка пустого массива как неопределенная переменная является действительно странным дизайном. –  Gilles 'SO- stop being evil' 28.11.2012, 00:19
  • 5
    , я предпочитаю результат: Как проверить, установлена ли переменная в Bash?-> Правильный путь... Я вызываю отклик в том, как я вещь это должно работать. Смейте я говорю, Windows имеет a defined оператор. Test мог СДЕЛАТЬ это; это не может быть трудно (гм....) большое спасибо –  will 11.04.2016, 17:48

Для подведения с ответом Gilles, я составил мой после правил:

  1. Использовать [[ -v foobar ]] для переменных в версии Bash> = 4.2.
  2. Использовать declare -p foobar &>/dev/null для переменных типа массив в версии Bash <4.2.
  3. Использовать (( ${foo[0]+1} )) или (( ${bar[foo]+1} )) для нижних индексов индексируемых (-a) и включенный (-A) массивы (declare), соответственно. Опции 1 и 2 не работают здесь.
5
27.01.2020, 19:48

Я использую ту же технику для всех переменных в ударе, и это работает, например:

[ ${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
3
27.01.2020, 19:48
  • 1
    Должен был удалить, если массив имеет больше чем одно значение. –  Stein Inge Morisbak 17.04.2013, 12:22
  • 2
    Это работает отлично, пока Вы хотите протестировать, имеет ли это значение, не, было ли это определено. Т.е. foobar="" затем сообщит это foobar is unset. Никакие не ожидают, я забираю это. Действительно только тесты, если первый элемент пуст или нет, таким образом, это, кажется, только хорошая идея, если Вы знаете переменную, НЕ являются массивом, и Вы только заботитесь о пустоте, не definedness. –  Ron Burk 15.06.2015, 05:00
  • 3
    только работает, если Ваши сценарии работают с позволенными неопределенными переменными (никакой набор-u) –  Florian Heigl 22.01.2018, 15:09

Теги

Похожие вопросы