Проверить, установлена ​​ли переменная в bash при использовании «set -o nounset»

99

Следующий код завершается с ошибкой несвязанной переменной. Как это исправить, продолжая использовать параметр set -oсуществительного?

#!/bin/bash

set -o nounset

if [ ! -z ${WHATEVER} ];
 then echo "yo"
fi

echo "whatever"
винодконе
источник

Ответы:

101
#!/bin/bash

set -o nounset


VALUE=${WHATEVER:-}

if [ ! -z ${VALUE} ];
 then echo "yo"
fi

echo "whatever"

В этом случае, VALUEесли WHATEVERне задано, становится пустой строкой . Мы используем {parameter:-word}расширение, которое вы можете найти в man bashразделе «Расширение параметров».

Ангелом
источник
15
просто замените, если [! -z $ {VALUE}]; с if [! -z $ {ЧТО: -}];
Angelom
18
:-проверяет, не задана ли переменная или пуста. Если вы хотите проверить только ли это снято с охраной, используйте -: VALUE=${WHATEVER-}. Кроме того, более читаемый способ проверить, пуста ли переменная:if [ "${WHATEVER+defined}" = defined ]; then echo defined; else echo undefined; fi
l0b0,
1
Кроме того, это не сработает, если $WHATEVERсодержит только пробелы - см. Мой ответ.
l0b0
11
Есть ли причина использовать " ! -z" вместо " -n"?
Джонатан Хартли
32

Вам нужно указать переменные, если вы хотите получить ожидаемый результат:

check() {
    if [ -n "${WHATEVER-}" ]
    then
        echo 'not empty'
    elif [ "${WHATEVER+defined}" = defined ]
    then
        echo 'empty but defined'
    else
        echo 'unset'
    fi
}

Контрольная работа:

$ unset WHATEVER
$ check
unset
$ WHATEVER=
$ check
empty but defined
$ WHATEVER='   '
$ check
not empty
l0b0
источник
Я попробовал это , и я удивлен это работает ... Все правильно , за исключением в соответствии "info bash", "${WHATEVER-}"должны иметь ":"(двоеточие) перед "-"(тире) , как: "${WHATEVER:-}"и "${WHATEVER+defined}"должны иметь двоеточие перед тем , "+"(плюс) , как: "${WHATEVER:+defined}". Для меня это работает в любом случае, с двоеточием или без него. В некоторых версиях nix это, вероятно, не будет работать без двоеточия, поэтому его, вероятно, следует добавить.
Кевин Феган
9
Неа, -, +, :+, и :-все поддерживаются. Первое обнаружение ли переменная установлена , а последний обнаруживает ли он установлен или пустой . From man bash: «Отсутствие двоеточия приводит к тестированию только для параметра, который не установлен».
l0b0 07
1
Забудь =). Ты прав. Не знаю, как я это пропустил.
Кевин Феган
Из документации : Другими словами, если двоеточие включено, оператор проверяет наличие обоих параметров и то, что его значение не равно нулю; если двоеточие опущено, оператор проверяет только наличие.
Acumenus
11

Как насчет одинарного лайнера?

[ -z "${VAR:-}" ] && echo "VAR is not set or is empty" || echo "VAR is set to $VAR"

-z проверяет наличие пустой или неустановленной переменной

NublaII
источник
2
Нет, -zтолько проверяет, пуст ли следующий параметр. -zэто просто аргумент [команды. Расширение переменной происходит раньше, чем [ -zможет что-либо сделать.
дольмен
1
Это кажется правильным решением, поскольку оно не генерирует ошибку, если $ VAR не установлен. @dolmen, можете ли вы привести пример, когда это не сработает?
Крис Стричински
@dolmen, прочитав различные ресурсы bash о расширении параметров и обнаружив, что другие ответы слишком сложны, я не вижу ничего плохого в этом. поэтому ваше «разъяснение», хотя и является технически правильным, на практике кажется довольно бессмысленным, если только вам не нужно различать неустановленное и пустое. Я тестировал неустановленные, пустые и непустые (bash 4), и каждый раз он делал то, что рекламировалось.
JL Peyret
9

Предположения:

$ echo $SHELL
/bin/bash
$ /bin/bash --version | head -1
GNU bash, version 4.1.2(1)-release (x86_64-redhat-linux-gnu)
$ set -o nounset

Если вы хотите, чтобы неинтерактивный сценарий выводил ошибку и завершал работу, если переменная имеет значение null или не задана:

$ [[ "${HOME:?}" ]]

$ [[ "${IAMUNBOUND:?}" ]]
bash: IAMUNBOUND: parameter null or not set

$ IAMNULL=""
$ [[ "${IAMNULL:?}" ]]
bash: IAMNULL: parameter null or not set

Если вы не хотите, чтобы сценарий завершился:

$ [[ "${HOME:-}" ]] || echo "Parameter null or not set."

$ [[ "${IAMUNBOUND:-}" ]] || echo "Parameter null or not set."
Parameter null or not set.

$ IAMNULL=""
$ [[ "${IAMUNNULL:-}" ]] || echo "Parameter null or not set."
Parameter null or not set.

Вы даже можете использовать [и ]вместо[[ и ]]выше, но последнее предпочтительнее в Bash.

Обратите внимание на то, что делает двоеточие выше. Из документов :

Другими словами, если двоеточие включено, оператор проверяет наличие обоих параметров и то, что его значение не равно нулю; если двоеточие опущено, оператор проверяет только наличие.

Очевидно, нет необходимости в -nили -z.

Таким образом, я обычно могу просто использовать [[ "${VAR:?}" ]]. Согласно примерам, это печатает ошибку и выходит, если переменная имеет значение NULL или не задана.

Acumenus
источник
4

Ты можешь использовать

if [[ ${WHATEVER:+$WHATEVER} ]]; then

но

if [[ "${WHATEVER:+isset}" == "isset" ]]; then

может быть более читабельным.

Алеш Фридл
источник
При сравнении строк следует использовать стандартный =оператор (POSIX) не ==для облегчения переносимости, а [вместо него, [[если это возможно.
Йенс
2
@Jens Вопрос специфичен для bash и включает set -o nounsetспецифичный для bash. Если вы поместите #!/bin/bashвверху скрипта, лучше всего использовать улучшения bash.
Бруно Броноски
0

Хотя это не совсем тот вариант использования, о котором просили выше, я обнаружил, что если вы хотите использовать nounset(или-u ), поведение по умолчанию - это то, что вы хотите: выйти из ненулевого значения с описательным сообщением.

Мне потребовалось достаточно времени, чтобы осознать это, и я решил, что это стоит опубликовать в качестве решения.

Если все, что вам нужно, - это повторить что-то еще при выходе или выполнить некоторую очистку, вы можете использовать ловушку.

В :-противном случае, вероятно, вам нужен оператор.

Макс Билески
источник