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

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

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

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

15 ответов

Решение

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

if [ -z "$VAR" ];

В 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} ]]

Переменная в 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}" = "" ] потому что первый аргумент [ ошибочно интерпретируется как -n оператор, а не строка.

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

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

export PORT=${MY_PORT:-5432}

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

Если вы заинтересованы в различении случаев пустого набора и незаданного состояния, посмотрите параметр -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

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

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

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

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

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

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

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

Вопрос состоит в том, как проверить, является ли переменная пустой строкой, и лучшие ответы уже даны для этого.
Но я попал сюда после того, как прошел период программирования на 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, любой, кто использует эту функцию, должен оценить этот риск и, возможно, решит отключить эти проверки, оставив только первую.

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

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

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

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

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

if [ "${VARIABLE}" == "" ]; then
  echo VARIABLE is empty
else
  echo VARIABLE is not empty
fi

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

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

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

#! /bin/bash
[ -z "$1" ] || some_command_that_needs_$1_parameter

Чтобы выяснить, пуста ли переменная «Foo», а также не содержит ли она пробелов (или пробелов, как ее называют некоторые).

       if [[ -n "${Foo/[ ]*\n/}" ]];then

    echo "Foo is not empty and contains non space characters"

fi


# Another way to solve the same problem: Take spaces out in Foo & check if Foo is empty

 if [[ -z "${Foo// }" ]];then

     echo "Foo is empty"

 fi

Я предпочитаю способ, которым PHP проверяет пустую переменную, как упомянул Лука в своем ответе . Но вместо использования отдельной функции я использую «фильтр», который наконец позволяет использовать обычные условия bash.

Представьте, что у вас есть bash-скрипт с таким разделом настроек:

      # enable test mode
dry_run=false

# overwrite files if they already exist
overwrite_files=true

Пользователи скрипта должны иметь возможность настроить его по своему усмотрению:

      dry_run=
dry_run=""
dry_run=0
dry_run="0"
dry_run=false
dry_run="false"
# or delete it completely

Итак, в самом разделе скрипта я делаю это:

      # check user settings
[[ $dry_run == 0 ]] || [[ $dry_run == false ]] && unset dry_run
[[ $overwrite_files == 0 ]] || [[ $overwrite_files == false ]] && unset overwrite_files

Теперь я могу быть уверен, что переменная существует с содержимым или нет, поэтому я могу использовать обычное условие вроде этого:

      if [[ $dry_run ]]; then
  echo "dry run is true"
else
  echo "dry run is false"
fi

PS Я пропустил фильтрацию «0.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

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

Другие вопросы по тегам