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


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.