Как определить, является ли переменная bash пустой?

766

Каков наилучший способ определить, является ли переменная в bash пустой ("")?

Я слышал, что рекомендуется делать if [ "x$variable" = "x" ]

Это правильный путь? (должно быть что-то более простое)

казарка
источник

Ответы:

1053

Это вернет true, если переменная не установлена ​​или установлена ​​в пустую строку ("").

if [ -z "$VAR" ];
duffbeer703
источник
14
Включает ли это значение, если переменная установлена ​​в значение ""?
Brent
11
Да, это ... "-z" проверяет строку нулевой длины.
Дэвид З
91
if [ ! -z "$VAR" ];
Аарон Копли
263
обратное -zэто-n if [ -n "$VAR" ];
Felipe Alvarez
19
Двойные кавычки гарантируют, что переменная не будет разделена. Простое $varв командной строке будет разбито пробелом на список параметров, в то время как "$var"всегда будет только один параметр. Заключение в кавычки переменных часто является хорошей практикой и не дает вам запутаться в именах файлов, содержащих пробелы (среди прочего). Пример: после этого a="x --help"попробуйте cat $a- он откроет вам страницу помощи для cat. Тогда попробуй cat "$a"- он (обычно) скажет cat: x --help: No such file or directory. Короче, цитируйте рано и часто цитируйте, и вы почти никогда не пожалеете об этом.
Score_Under
247

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

Любое из следующего:

if [[ -z $variable ]]
if [[ -z "$variable" ]]
if [[ ! $variable ]]
if [[ ! "$variable" ]]

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

if [[ $variable ]]

Этот синтаксис совместим с ksh (по крайней мере, ksh93, в любом случае). Он не работает в чистых оболочках POSIX или старых Bourne, таких как sh или dash.

Смотрите мой ответ здесь и BashFAQ / 031 для получения дополнительной информации о различиях между двойными и одинарными квадратными скобками.

Вы можете проверить, является ли переменная не установленной (в отличие от пустой строки):

if [[ -z ${variable+x} ]]

где «х» является произвольным.

Если вы хотите узнать, является ли переменная нулевой, но не не установлена ​​ли она:

if [[ -z $variable && ${variable+x} ]]
Деннис Уильямсон
источник
1
Это if [[ $variable ]]работало хорошо для меня, и даже не нуждалось в том, set -uчто требовалось одним из других предложенных решений.
Теему Лейсти
3
Я думаю, что это лучше, чем принятый ответ.
13:00
2
Почему вы рекомендуете непереносную функцию, если это не дает никакой выгоды?
Аластер Ирвин
19
@AlastairIrvine: я упоминаю о переносимости в первом предложении моего ответа, заголовок и тело вопроса содержат слово «Bash», а вопрос помечен как « bash» , а структура с двумя скобками обеспечивает явные преимущества во многих отношениях. И я не рекомендую смешивать стили скобок из соображений согласованности и ремонтопригодности. Если вам нужна максимальная переносимость наименьшего общего знаменателя, используйте shвместо Bash. Если вам нужны расширенные возможности, которые он предоставляет, используйте Bash и используйте его полностью.
Деннис Уильямсон,
2
@BrunoBronosky: я отменил редактирование. Там нет требования для ;в конце. thenМожет быть на следующей строке без запятой вообще.
Деннис Уильямсон
230

Переменная в bash (и любая POSIX-совместимая оболочка) может находиться в одном из трех состояний:

  • снята с охраны
  • установить пустую строку
  • установить непустую строку

В большинстве случаев вам нужно только знать, установлена ​​ли переменная в непустую строку, но иногда важно различать unset и задавать пустую строку.

Ниже приведены примеры того, как вы можете протестировать различные возможности, и это работает в bash или любой POSIX-совместимой оболочке:

if [ -z "${VAR}" ]; then
    echo "VAR is unset or set to the empty string"
fi
if [ -z "${VAR+set}" ]; then
    echo "VAR is unset"
fi
if [ -z "${VAR-unset}" ]; then
    echo "VAR is set to the empty string"
fi
if [ -n "${VAR}" ]; then
    echo "VAR is set to a non-empty string"
fi
if [ -n "${VAR+set}" ]; then
    echo "VAR is set, possibly to the empty string"
fi
if [ -n "${VAR-unset}" ]; then
    echo "VAR is either unset or set to a non-empty string"
fi

Вот то же самое, но в удобной форме таблицы:

                        +-------+-------+-----------+
                VAR is: | unset | empty | non-empty |
+-----------------------+-------+-------+-----------+
| [ -z "${VAR}" ]       | true  | true  | false     |
| [ -z "${VAR+set}" ]   | true  | false | false     |
| [ -z "${VAR-unset}" ] | false | true  | false     |
| [ -n "${VAR}" ]       | false | false | true      |
| [ -n "${VAR+set}" ]   | false | true  | true      |
| [ -n "${VAR-unset}" ] | true  | false | true      |
+-----------------------+-------+-------+-----------+

${VAR+foo}Конструкция раскрывается в пустую строку , если VARона не задана , или fooесли VARустановлено что - то ( в том числе пустая строка).

${VAR-foo}Конструкция расширяется до значения , VARесли установлено ( в том числе установить в пустую строку) и fooесли не задано. Это полезно для обеспечения переопределяемых пользователем значений по умолчанию (например, ${COLOR-red}говорит , что использовать, redесли переменная COLORне была установлена ​​на что-то).

Причина, по которой [ x"${VAR}" = x ]часто рекомендуется проверять, является ли переменная неустановленной или установлена ​​в пустую строку, заключается в том, что некоторые реализации [команды (также известные как test) содержат ошибки. Если VARустановлено что-то вроде -n, то некоторые реализации будут делать неправильно, когда дано, [ "${VAR}" = "" ]потому что первый аргумент to [ошибочно интерпретируется как -nоператор, а не строка.

Ричард Хансен
источник
3
Тестирование переменной, для которой задана пустая строка, также можно выполнить с помощью [ -z "${VAR-set}" ].
nwellnhof
@nwellnhof: Спасибо! Я обновил свой ответ, чтобы использовать более короткий синтаксис.
Ричард Хансен
В чем разница между первой и последней конструкцией? Они оба соответствуют «VAR либо не установлен, либо установлен в непустую строку».
Фахим Митха
1
@FaheemMitha: Это не твоя вина - мой ответ было трудно прочитать. Я добавил таблицу, чтобы, надеюсь, сделать ответ более понятным.
Ричард Хансен
2
Неустановленные проверки не надежны. Если пользователь вызвал set -uили set -o nounsetв bash, то проверка просто выдаст ошибку «bash: VAR: unbound variable». См. Stackoverflow.com/a/13864829 для более надежной проверки сброса. Моя проверка, является ли переменная нулевой или неустановленной [ -z "${VAR:-}" ]. Моя проверка , является ли переменная непустое это [ "${VAR:-}" ].
Кевин Джин
38

-z это лучший способ.

Другие опции, которые я использовал, это установить переменную, но она может быть переопределена другой переменной, например

export PORT=${MY_PORT:-5432}

Если $MY_PORTпеременная пуста, то PORTустанавливается значение 5432, в противном случае значение PORT устанавливается равным значению MY_PORT. Обратите внимание, синтаксис включает двоеточие и тире.

Рори
источник
Случайно нашел это сегодня, и это было именно то, что я хотел. Спасибо! Я должен терпеть set -o nounsetв некоторых сценариях.
opello
24

Если вы заинтересованы в различении случаев пустого набора и незаданного состояния, посмотрите параметр -u для bash:

$ set -u
$ echo $BAR
bash: BAR: unbound variable
$ [ -z "$BAR" ] && echo true
bash: BAR: unbound variable
$ BAR=""
$ echo $BAR

$ [ -z "$BAR" ] && echo true
true
MikeyB
источник
8

Альтернативой, которую я видел, [ -z "$foo" ]является следующее, однако я не уверен, почему люди используют этот метод, кто-нибудь знает?

[ "x${foo}" = "x" ]

В любом случае, если вы не разрешите неустановленные переменные (либо с помощью, set -uлибо set -o nounset), то у вас возникнут проблемы с обоими этими методами. Это простое решение:

[ -z "${foo:-}" ]

Примечание: это оставит вашу переменную undef.

errant.info
источник
3
Есть комментарий об альтернативе -zна pubs.opengroup.org/onlinepubs/009695399/utilities/test.html . По сути, это не означает, что является альтернативой -z. Скорее, он обрабатывает случаи, когда $fooможет расшириться до чего-то, начинающегося с метасимвола, который [или testбудет смущен. Помещение произвольного неметасимвола в начале исключает эту возможность.
Джеймс Снерингер
6

Вопрос спрашивает , как проверить , является ли переменная пустая строка и лучшие ответы уже даны для этого.
Но я попал сюда после того, как прошел период программирования на php, и то, что я действительно искал, было проверкой, похожей на пустую функцию в php, работающую в оболочке bash.
Прочитав ответы, я понял, что не думаю о bash должным образом, но в любом случае в моем bash-коде такая функция, как empty в php, была бы очень удобной.
Поскольку я думаю, что это может случиться с другими, я решил преобразовать пустую функцию php в bash

Согласно руководству по php :
переменная считается пустой, если она не существует или если ее значение является одним из следующих:

  • «» (пустая строка)
  • 0 (0 как целое число)
  • 0.0 (0 как поплавок)
  • «0» (0 как строка)
  • пустой массив
  • объявленная переменная, но без значения

Конечно, нулевые и ложные случаи не могут быть преобразованы в bash, поэтому они опущены.

function empty
{
    local var="$1"

    # Return true if:
    # 1.    var is a null string ("" as empty string)
    # 2.    a non set variable is passed
    # 3.    a declared variable or array but without a value is passed
    # 4.    an empty array is passed
    if test -z "$var"
    then
        [[ $( echo "1" ) ]]
        return

    # Return true if var is zero (0 as an integer or "0" as a string)
    elif [ "$var" == 0 2> /dev/null ]
    then
        [[ $( echo "1" ) ]]
        return

    # Return true if var is 0.0 (0 as a float)
    elif [ "$var" == 0.0 2> /dev/null ]
    then
        [[ $( echo "1" ) ]]
        return
    fi

    [[ $( echo "" ) ]]
}



Пример использования:

if empty "${var}"
    then
        echo "empty"
    else
        echo "not empty"
fi



Демо:
следующий фрагмент:

#!/bin/bash

vars=(
    ""
    0
    0.0
    "0"
    1
    "string"
    " "
)

for (( i=0; i<${#vars[@]}; i++ ))
do
    var="${vars[$i]}"

    if empty "${var}"
        then
            what="empty"
        else
            what="not empty"
    fi
    echo "VAR \"$var\" is $what"
done

exit

выходы:

VAR "" is empty
VAR "0" is empty
VAR "0.0" is empty
VAR "0" is empty
VAR "1" is not empty
VAR "string" is not empty
VAR " " is not empty

Сказав, что в логике bash проверки на ноль в этой функции могут вызвать побочные проблемы imho, любой, кто использует эту функцию, должен оценить этот риск и, возможно, решит отключить эти проверки, оставив только первую.

Люка Боррионе
источник
Внутри функции empty- почему вы пишете, [[ $( echo "1" ) ]] ; returnа не просто return 1?
Дор
5

все if-then и -z не нужны.

["$ foo"] && echo "foo не пустой"
["$ foo"] || echo "foo действительно пусто"

источник
3
Это потерпит неудачу, если foo содержит только пробелы
Брайан
2
Также произойдет сбой в некоторых оболочках, если foo начинается с тире, так как это интерпретируется как опция. Например, в Solaris ksh , zsh и bash не проблема, sh и / bin / test завершатся неудачей
ktf
4

Это верно именно тогда, когда $ FOO установлен и пуст:

[ "${FOO+x}" = x ] && [ -z "$FOO" ]

источник
4

Лично предпочитаю более понятный способ проверки:

if [ "${VARIABLE}" == "" ]; then
  echo VARIABLE is empty
else
  echo VARIABLE is not empty
fi
Федир РЫХТИК
источник
1
Некоторые оболочки не принимают двойной знак равенства.
Деннис Уильямсон
1
Вопрос был о баш. Я использую Bash. Хорошо работает для меня. О чем именно Вы говорите?
Федир Рыхтик
2
Если вы используете Bash, вы должны использовать двойные квадратные скобки. Мой предыдущий комментарий был простой констатацией факта для тех, кто может прочитать ваш ответ и использовать другую оболочку.
Деннис Уильямсон
в этом случае можно использовать квадратные скобки, см. serverfault.com/questions/52034/…
Лука Боррионе
4

Расширение oneliner решения duffbeer703 :

#! /bin/bash
[ -z "$1" ] || some_command_that_needs_$1_parameter
андрей
источник
4

Мои 5 центов: есть также более короткий синтаксис, чем if ...этот:

VALUE="${1?"Usage: $0 value"}"

Эта строка установит VALUE, если был предоставлен аргумент, и напечатает сообщение об ошибке с добавлением номера строки сценария в случае ошибки (и прекратит выполнение сценария).

Другой пример можно найти в руководстве по abs (поиск «Пример 10-7»).

gluk47
источник
0

Не точный ответ, но наткнулся на этот трюк. Если искомая строка взята из «команды», вы можете сохранить команду в env. переменной, а затем выполняйте ее каждый раз для оператора if, тогда скобки не требуются!

Например, эта команда, которая определяет, используете ли вы Debian:

grep debian /proc/version

полный пример:

IS_DEBIAN="grep -i debian /proc/version"

if $IS_DEBIAN; then
  echo 'yes debian'
else
  echo 'non debian'
fi

Так что это похоже на косвенный способ (повторный запуск каждый раз), чтобы проверить пустую строку (это происходит проверка ответа на ошибку от команды, но это также происходит, чтобы вернуть пустую строку).

rogerdpack
источник