Как определить, не определена ли строка в оболочке bash script?

Если я хочу проверить нулевую строку, я бы сделал

[ -z $mystr ]

но что, если я хочу проверить, была ли вообще определена переменная? Или нет различий в сценариях bash?

Ответ 1

Я думаю, что ответ, который вам нужен, подразумевается (если не указано) Vinko answer, хотя это не прописано просто. Чтобы определить, установлен ли VAR, но пустой или не установлен, вы можете использовать:

if [ -z "${VAR+xxx}" ]; then echo VAR is not set at all; fi
if [ -z "$VAR" ] && [ "${VAR+xxx}" = "xxx" ]; then echo VAR is set but empty; fi

Вероятно, вы можете объединить два теста во второй строке с одним:

if [ -z "$VAR" -a "${VAR+xxx}" = "xxx" ]; then echo VAR is set but empty; fi

Однако, если вы прочитаете документацию для Autoconf, вы обнаружите, что они не рекомендуют комбинировать термины с "-a" и рекомендуют использовать отдельные простые тесты в сочетании с &&. Я не сталкивался с системой, в которой есть проблема; это не значит, что они не существовали (но в наши дни они, вероятно, крайне редки, даже если они были не такими редкими в далеком прошлом).

Вы можете найти подробную информацию об этих и других связанных расширениях параметров оболочки, test или [ и условные выражения в руководстве Bash.


Недавно я спросил по электронной почте об этом ответе на вопрос:

Вы используете два теста, и я понимаю второй, но не первый. Точнее, я не понимаю необходимости расширения переменных

if [ -z "${VAR+xxx}" ]; then echo VAR is not set at all; fi

Разве это не будет достигнуто?

if [ -z "${VAR}" ]; then echo VAR is not set at all; fi

Справедливый вопрос - ответ "Нет, ваша простая альтернатива не делает то же самое".

Предположим, что я пишу это перед вашим тестом:

VAR=

В вашем тесте будет указано, что "VAR не установлен вообще", но мой скажет (подразумевается, потому что он ничего не повторяет) "VAR установлен, но его значение может быть пустым". Попробуйте script:

(
unset VAR
if [ -z "${VAR+xxx}" ]; then echo JL:1 VAR is not set at all; fi
if [ -z "${VAR}" ];     then echo MP:1 VAR is not set at all; fi
VAR=
if [ -z "${VAR+xxx}" ]; then echo JL:2 VAR is not set at all; fi
if [ -z "${VAR}" ];     then echo MP:2 VAR is not set at all; fi
)

Вывод:

JL:1 VAR is not set at all
MP:1 VAR is not set at all
MP:2 VAR is not set at all

Во второй паре тестов задана переменная, но она установлена ​​в пустое значение. Это различие, которое делают обозначения ${VAR=value} и ${VAR:=value}. Тоже для ${VAR-value} и ${VAR:-value}, и ${VAR+value} и ${VAR:+value} и т.д.


Как Gili указывает в ответе , если вы запустите bash с помощью set -o nounset, тогда основной ответ выше не с unbound variable. Это легко исправить:

if [ -z "${VAR+xxx}" ]; then echo VAR is not set at all; fi
if [ -z "${VAR-}" ] && [ "${VAR+xxx}" = "xxx" ]; then echo VAR is set but empty; fi

Или вы можете отменить параметр set -o nounset, если set +u (set -u эквивалентен set -o nounset).

Ответ 2

~> if [ -z $FOO ]; then echo "EMPTY"; fi
EMPTY
~> FOO=""
~> if [ -z $FOO ]; then echo "EMPTY"; fi
EMPTY
~> FOO="a"
~> if [ -z $FOO ]; then echo "EMPTY"; fi
~> 

-z также работает для переменных undefined. Чтобы различать undefined и определенный, вы должны использовать перечисленные ниже вещи здесь или, с более ясными объяснениями, здесь.

Самый чистый способ - использовать расширение, как в этих примерах. Чтобы получить все ваши варианты, проверьте раздел "Расширение параметров" руководства.

Альтернативное слово:

~$ unset FOO
~$ if test ${FOO+defined}; then echo "DEFINED"; fi
~$ FOO=""
~$ if test ${FOO+defined}; then echo "DEFINED"; fi
DEFINED

Значение по умолчанию:

~$ FOO=""
~$ if test "${FOO-default value}" ; then echo "UNDEFINED"; fi
~$ unset FOO
~$ if test "${FOO-default value}" ; then echo "UNDEFINED"; fi
UNDEFINED

Конечно, вы бы использовали один из них по-другому, поставив нужное значение вместо значения по умолчанию и используя расширение, если это необходимо.

Ответ 3

Расширенный bash скриптовый путеводитель, 10.2. Замена параметра:

  • ${var + blahblah}: если var определено, 'blahblah' заменяется на выражение, else null заменяется
  • ${var-blahblah}: если var определен, он сам заменяется, иначе 'blahblah' подставляется
  • ${var? blahblah}: если var определен, он заменяется, иначе функция существует с сообщением "blahblah".


чтобы основывать свою программную логику на том, определена ли переменная $mystr или нет, вы можете сделать следующее:

isdefined=0
${mystr+ export isdefined=1}

теперь, если isdefined = 0, тогда переменная была undefined, если isdefined = 1, была определена переменная

Этот способ проверки переменных лучше, чем приведенный выше ответ, потому что он более изящный, читаемый, и если ваша оболочка bash была настроена на ошибку при использовании переменных undefined (set -u), script будет прекратите преждевременно.


Другие полезные материалы:

чтобы иметь значение по умолчанию 7, присвоенное $mystr, если оно было undefined, и оставить его неповрежденным иначе:

mystr=${mystr- 7}

чтобы напечатать сообщение об ошибке и выйти из функции, если переменная undefined:

: ${mystr? not defined}

Остерегайтесь здесь, что я использовал ':', чтобы не иметь содержимое $mystr, выполненного как команда, если оно определено.

Ответ 4

Резюме тестов.

[ -n "$var" ] && echo "var is set and not empty"
[ -z "$var" ] && echo "var is unset or empty"
[ "${var+x}" = "x" ] && echo "var is set"  # may or may not be empty
[ -n "${var+x}" ] && echo "var is set"  # may or may not be empty
[ -z "${var+x}" ] && echo "var is unset"
[ -z "${var-x}" ] && echo "var is set and empty"

Ответ 5

fooobar.com/questions/8695/... содержит лучший ответ (тот, который более читабельен и работает с set -o nounset включен). Он работает примерно так:

if [ -n "${VAR-}" ]; then
    echo "VAR is set and is not empty"
elif [ "${VAR+DEFINED_BUT_EMPTY}" = "DEFINED_BUT_EMPTY" ]; then
    echo "VAR is set, but empty"
else
    echo "VAR is not set"
fi

Ответ 6

Явным способом проверить, будет ли определена переменная, будет:

[ -v mystr ]

Ответ 7

еще одна опция: расширение индексов массива":

$ unset foo
$ foo=
$ echo ${!foo[*]}
0
$ foo=bar
$ echo ${!foo[*]}
0
$ foo=(bar baz)
$ echo ${!foo[*]}
0 1

единственный раз, когда это расширится до пустой строки, это когда foo не задано, поэтому вы можете проверить его со строкой условным:

$ unset foo
$ [[ ${!foo[*]} ]]; echo $?
1
$ foo=
$ [[ ${!foo[*]} ]]; echo $?
0
$ foo=bar
$ [[ ${!foo[*]} ]]; echo $?
0
$ foo=(bar baz)
$ [[ ${!foo[*]} ]]; echo $?
0

должен быть доступен в любой версии bash > 3.0

Ответ 8

не пропустить этот байк еще больше, но хотел добавить

shopt -s -o nounset

- это то, что вы могли бы добавить в начало script, что приведет к ошибке, если переменные не объявлены нигде в script. Сообщение, которое вы видите, это unbound variable, но, как говорят другие, оно не будет ловить пустую строку или нулевое значение. Чтобы убедиться, что какое-либо индивидуальное значение не пусто, мы можем протестировать переменную по мере ее расширения с помощью ${mystr:?}, также известного как расширение знака доллара, что приведет к ошибке с parameter null or not set.

Ответ 9

Справочное руководство Bash является авторитетным источником информации о bash.

Здесь приведен пример тестирования переменной, чтобы увидеть, существует ли она:

if [ -z "$PS1" ]; then
        echo This shell is not interactive
else
        echo This shell is interactive
fi

(Из раздел 6.3.2.)

Обратите внимание, что пробелы после открытого [ и до ] не являются необязательными.


Советы для пользователей Vim

У меня был script, у которого было несколько объявлений:

export VARIABLE_NAME="$SOME_OTHER_VARIABLE/path-part"

Но я хотел, чтобы они относились к любым существующим ценностям. Поэтому я переписал их так:

if [ -z "$VARIABLE_NAME" ]; then
        export VARIABLE_NAME="$SOME_OTHER_VARIABLE/path-part"
fi

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

s/\vexport ([A-Z_]+)\=("[^"]+")\n/if [ -z "$\1" ]; then\r  export \1=\2\rfi\r/gc

Это можно применить, визуально выбрав соответствующие строки, затем набрав :. Панель команд предварительно заполняет кнопкой :'<,'>. Вставьте указанную выше команду и нажмите enter.


Протестировано на этой версии Vim:

VIM - Vi IMproved 7.3 (2010 Aug 15, compiled Aug 22 2015 15:38:58)
Compiled by [email protected]

Пользователям Windows могут потребоваться разные окончания строк.

Ответ 10

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

var_defined() {
    local var_name=$1
    set | grep "^${var_name}=" 1>/dev/null
    return $?
}

Используйте его следующим образом:

if var_defined foo; then
    echo "foo is defined"
else
    echo "foo is not defined"
fi

Ответ 11

набор вызовов без каких-либо аргументов.. он выводит все определенные вары..
последними в списке будут те, которые определены в вашем script..
так что вы могли бы вывести свой вывод на что-то, что могло бы определить, какие вещи определены, а что нет