Як визначити, чи базова змінна порожня?


765

Який найкращий спосіб визначити, чи змінна в bash порожня ("")?

Я чув, що мені це рекомендується робити if [ "x$variable" = "x" ]

Це правильний шлях? (повинно бути щось простіше)


Відповіді:


1053

Це повернеться true, якщо змінна не встановлена ​​або встановлена ​​у порожній рядок ("").

if [ -z "$VAR" ];

14
Чи включає це, якщо змінна IS SET до значення ""?
Brent

11
Так, це робить ... "-z" тести для рядка нульової довжини.
David Z

91
if [ ! -z "$VAR" ];
Аарон Коплі

263
зворотним -zє-n if [ -n "$VAR" ];
Феліпе Альварес

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 або старих оболонках Борна, таких як sh або dash.

Дивіться мою відповідь тут і BashFAQ / 031 для отримання додаткової інформації про відмінності між подвійними та одинарними квадратними дужками.

Ви можете перевірити, чи змінена конкретна змінна (на відміну від порожнього рядка):

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

де "х" довільне.

Якщо ви хочете дізнатися, чи є змінна нульовою, але не скасована:

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

1
Це if [[ $variable ]]добре працювало для мене і навіть не потребувало того, set -uщо вимагало одне з інших запропонованих рішень.
Teemu Leisti

3
Я думаю, це краще, ніж прийнята відповідь.
qed

2
Чому ви рекомендуєте не переносити функцію, коли це не дає користі?
Аластер Ірвін

19
@AlastairIrvine: Я згадую про переносимість у першому реченні своєї відповіді, назва і тіло питання містять слово "Bash", а питання позначається bash , а структура подвійної дужки багато в чому забезпечує чіткі переваги . І я не рекомендую змішувати стилі дужок з міркувань послідовності та ремонтопридатності. Якщо вам потрібна максимальна, найнижча портативність загального знаменника, використовуйте shзамість Bash. Якщо вам потрібні розширені можливості, які він надає, використовуйте Bash і використовуйте його повністю.
Денніс Вільямсон

2
@BrunoBronosky: я змінив правки. В ;кінці немає ніяких вимог . На thenнаступному рядку може бути зовсім без крапки з комою.
Денніс Вільямсон

230

Змінна в bash (і будь-якій сумісній з POSIX оболонці) може бути в одному з трьох станів:

  • невстановлений
  • встановити порожній рядок
  • встановлено не порожній рядок

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

Нижче наведено приклади того, як ви можете перевірити різні можливості, і він працює в 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оператор, а не рядок.


3
Тестування змінної, встановленої в порожній рядок, також можна проводити, використовуючи [ -z "${VAR-set}" ].
nwellnhof

@nwellnhof: Дякую! Я оновив свою відповідь, щоб використовувати синтаксис briefer.
Річард Хансен

Яка різниця між першою та останньою конструкцією? Вони обидва відповідають "ВАР або знято, або встановлено не порожній рядок".
Faheem Mitha

1
@FaheemMitha: Ви не винні - мою відповідь важко було прочитати. Я додав таблицю, щоб сподіватися зробити відповідь більш зрозумілою.
Річард Хансен

2
Невстановлені чеки не є надійними. Якщо користувач зателефонував set -uабо set -o nounsetв bash, тест просто призведе до помилки "bash: VAR: unbound змінної". Дивіться 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

8

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

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

У будь-якому випадку, якщо ви забороняєте невстановлені змінні (або через, set -uабо set -o nounset), у вас виникнуть проблеми з обома цими методами. Існує просте виправлення цього:

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

Примітка. Це змінить вашу змінну undef.


3
Є коментар про альтернативу на веб- -zсайті pubs.opengroup.org/onlinepubs/009695399/utilities/test.html . В основному, це не означає, що це альтернатива -z. Скоріше, він обробляє випадки, коли $fooможе розширюватися до чогось, починаючи з метахарактера, який би [або testплутав. Поставлення довільного неметахара на початку виключає таку можливість.
Джеймс Снерінгер

6

Питання запитує , як перевірити , чи є змінна порожній рядок і кращі відповіді вже дані для цього.
Але я приземлився сюди після періоду, який пройшов програмування в php, і те, що я насправді шукав, було перевірки, як порожня функція в php, що працює в оболонці bash.
Прочитавши відповіді, я зрозумів, що не думаю належним чином в баші, але все одно в цей момент така функція, як порожня в 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

Сказавши, що в логіці баша перевірка нуля в цій функції може викликати побічні проблеми, будь-хто, хто використовує цю функцію, повинен оцінити цей ризик і, можливо, вирішить скоротити ці чеки, залишивши лише перший.


Всередині функції empty- чому ви писали [[ $( echo "1" ) ]] ; returnзамість просто return 1?
Дор

5

цілі if-тоді і -z непотрібні.

["$ foo"] && echo "foo не порожній"
["$ foo"] || відлуння "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/…
Luca


4

Мої 5 центів: також є коротший синтаксис, ніж if ...цей:

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

Цей рядок встановить VALUE, якщо аргумент наданий, і буде надруковано повідомлення про помилку, попередньо вказане з номером рядка сценарію, у разі помилки (і завершить виконання сценарію).

Інший приклад можна знайти в путівнику abs (пошук «Приклад 10-7»).


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

Отже, це як непрямий спосіб (щоразу повторюючи його) для перевірки порожнього рядка (трапляється, що перевірка на відповідь про помилку з команди, але також буває повернення порожнього рядка).

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.