Если я хочу проверить нулевую строку, я бы сделал
[ -z $mystr ]
но что, если я хочу проверить, была ли вообще определена переменная? Или нет различий в сценариях bash?
Если я хочу проверить нулевую строку, я бы сделал
[ -z $mystr ]
но что, если я хочу проверить, была ли вообще определена переменная? Или нет различий в сценариях bash?
Я думаю, что ответ, который вам нужен, подразумевается (если не указано) 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
).
~> 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
Конечно, вы бы использовали один из них по-другому, поставив нужное значение вместо значения по умолчанию и используя расширение, если это необходимо.
Расширенный bash скриптовый путеводитель, 10.2. Замена параметра:
чтобы основывать свою программную логику на том, определена ли переменная $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, выполненного как команда, если оно определено.
Резюме тестов.
[ -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"
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
Явным способом проверить, будет ли определена переменная, будет:
[ -v mystr ]
еще одна опция: расширение индексов массива":
$ 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
не пропустить этот байк еще больше, но хотел добавить
shopt -s -o nounset
- это то, что вы могли бы добавить в начало script, что приведет к ошибке, если переменные не объявлены нигде в script. Сообщение, которое вы видите, это unbound variable
, но, как говорят другие, оно не будет ловить пустую строку или нулевое значение. Чтобы убедиться, что какое-либо индивидуальное значение не пусто, мы можем протестировать переменную по мере ее расширения с помощью ${mystr:?}
, также известного как расширение знака доллара, что приведет к ошибке с parameter null or not set
.
Справочное руководство 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 могут потребоваться разные окончания строк.
Вот что я думаю, это гораздо более четкий способ проверить, определена ли переменная:
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
набор вызовов без каких-либо аргументов.. он выводит все определенные вары..
последними в списке будут те, которые определены в вашем script..
так что вы могли бы вывести свой вывод на что-то, что могло бы определить, какие вещи определены, а что нет