пожалуйста, имейте привычку использовать [-z "$ mystr"] вместо [-z $ mystr]
Чарльз Даффи
как сделать обратную вещь? Я имею в виду, когда строка не нулевая
Откройте путь
1
@flow: Как насчет[ -n "${VAR+x}"] && echo not null
Лекенштейн
1
@CharlesDuffy Я читал это раньше на многих онлайн-ресурсах. Почему это предпочтительнее?
ffledgling
6
@Ayos, потому что, если у вас нет кавычек, содержимое переменной разбивается на строки и разбивается; если это пустая строка, она становится [ -z ]вместо [ -z "" ]; если у него есть пробелы, он становится [ -z "my" "test" ]вместо [ -z my test ]; и если это так [ -z * ], то имя *заменяется именами файлов в вашем каталоге.
Чарльз Даффи
Ответы:
138
Я думаю , что ответ вы после Подразумевается (если не указано иное) на Винко «s ответ , хотя это не прописано просто. Чтобы определить, установлен ли VAR, но не указан или нет, вы можете использовать:
if[-z "${VAR+xxx}"];then echo VAR is not set at all;fiif[-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' и рекомендуют использовать отдельные простые тесты в сочетании с &&. Я не сталкивался с системой, где есть проблема; это не значит, что они не существовали (но они, вероятно, чрезвычайно редки в наши дни, даже если они не были такими редкими в далеком прошлом).
Меня недавно спросили по электронной почте об этом ответе с вопросом:
Вы используете два теста, и я хорошо понимаю второй, но не первый. Точнее я не понимаю необходимости расширения переменной
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 установлен, но его значение может быть пустым». Попробуйте этот скрипт:
(
unset VAR
if[-z "${VAR+xxx}"];then echo JL:1 VAR is not set at all;fiif[-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;fiif[-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}, и так далее.
Как указывает в своем ответе Гили , если вы запускаете с опцией, то основной ответ выше не с . Это легко исправить:bashset -o nounsetunbound variable
if[-z "${VAR+xxx}"];then echo VAR is not set at all;fiif[-z "${VAR-}"]&&["${VAR+xxx}"="xxx"];then echo VAR is set but empty;fi
Или вы можете отменить set -o nounsetопцию с помощью set +u( set -uэквивалентно set -o nounset).
Единственная проблема, с которой я сталкиваюсь в этом ответе, заключается в том, что он выполняет свою задачу довольно косвенным и неясным образом.
Швейцарский
3
Для тех, кто хочет посмотреть описание того, что выше означает на странице руководства bash, поищите раздел «Расширение параметров», а затем следующий текст: «Если не выполняется раскрытие подстроки, используя формы, описанные ниже, тесты bash для параметр, который не установлен или имеет значение null ['null', означающее пустую строку]. Пропуск двоеточия приводит к проверке только для параметра, который не установлен (...) $ {параметр: + слово}: использовать альтернативное значение. Если параметр имеет значение null или unset, ничего не подставляется, в противном случае подставляется расширение слова. "
Дэвид Тонхофер
2
@ Swiss Это не является ни непонятным, ни косвенным, но идиоматическим. Возможно, для программиста, незнакомого с этим, ${+}и ${-}неясно, но знакомство с этими конструкциями необходимо для того, чтобы быть компетентным пользователем оболочки.
Я сделал много испытаний по этому вопросу; потому что результаты в моих сценариях были несоответствующими. Я предлагаю людям взглянуть на " [ -v VAR ]" подход с bash -s v4.2 и выше .
-z работает и для неопределенных переменных. Чтобы различать неопределенное и определенное, вы должны использовать перечисленные здесь вещи или, с более понятными объяснениями, здесь .
Самый чистый способ - использовать расширение, как в этих примерах. Чтобы получить все ваши варианты, обратитесь к разделу «Расширение параметров» в руководстве.
Альтернативное слово:
~$ 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
Конечно, вы бы использовали один из них по-другому, поместив желаемое значение вместо «значение по умолчанию» и используя расширение, если это необходимо.
Но я хочу различать, является ли строка "" или не была определена когда-либо. Это возможно?
Setjmp
1
этот ответ действительно сказать , как различать эти два случая; перейдите по ссылке bash faq для дальнейшего обсуждения.
Чарльз Даффи
1
Я добавил, что после его комментария Чарльз
Винко Врсалович
2
Посмотрите "Расширение параметров" на странице руководства bash для всех этих "уловок". Например, $ {foo: -default} для использования значения по умолчанию, $ {foo: = default} для назначения значения по умолчанию, $ {foo:? Message error} для отображения сообщения об ошибке, если foo не установлен и т. Д.
Jouni K Сеппанен
18
Расширенное руководство по написанию сценариев, 10.2. Подстановка параметров:
$ {var + blahblah}: если определено var, вместо выражения подставляется «blahblah», иначе подставляется нуль
$ {var-blahblah}: если переменная определена, она сама подставляется, иначе подставляется «blahblah»
$ {var? blahblah}: если переменная определена, она подставляется, иначе функция существует с 'blahblah' в качестве сообщения об ошибке.
Чтобы основать логику вашей программы на том, определена переменная $ mystr или нет, вы можете сделать следующее:
isdefined=0
${mystr+ export isdefined=1}
теперь, если isdefined = 0, тогда переменная была неопределенной, если isdefined = 1, переменная была определена
Этот способ проверки переменных лучше, чем приведенный выше ответ, поскольку он более элегантен, удобочитаем, и если ваша оболочка bash была настроена на ошибку при использовании неопределенных переменных (set -u), сценарий завершится преждевременно.
Другие полезные вещи:
иметь значение по умолчанию 7, присвоенное $ mystr, если оно не было определено, и оставить его нетронутым в противном случае:
mystr=${mystr-7}
распечатать сообщение об ошибке и выйти из функции, если переменная не определена:
: ${mystr? not defined}
Остерегайтесь здесь того, что я использовал ':', чтобы содержимое $ mystr не выполнялось как команда, если оно определено.
Я не знал о? синтаксис для переменных BASH. Это хороший улов.
Швейцарский
Это работает также с косвенными ссылками на переменные. Это проходит: var= ; varname=var ; : ${!varname?not defined}и это заканчивается: varname=var ; : ${!varname?not defined}. Но это хорошая привычка, set -uкоторая делает то же самое намного проще.
ceving
11
Краткое содержание тестов.
[-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"
Хорошая практика в Bash. Иногда пути к файлам имеют пробелы или для защиты от внедрения команд
k107
1
Я думаю, ${var+x}что в этом нет необходимости, за исключением случаев, когда имена переменных могут содержать пробелы.
Энн ван Россум
Не просто хорошая практика; это требуется с , [чтобы получить правильные результаты. Если varне установлено или пусто, [ -n $var ]сводится к тому, [ -n ]что имеет выходной статус 0, а [ -n "$var" ]ожидаемый (и правильный) выходной статус
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
Не могу найти это ни на одной из man-страниц (для bash или test), но это работает для меня .. Есть идеи, какие версии это было добавлено?
Эш Берлин-Тейлор
1
Он задокументирован в условных выражениях , на которые ссылается testоператор в хвостовой части раздела Bourne Shell Builtins . Я не знаю, когда он был добавлен, но его нет в версии Apple bash(основанной на bash3.2.51), так что это, вероятно, функция 4.x.
Джонатан Леффлер
1
Это не работает для меня GNU bash, version 4.1.2(1)-release (x86_64-redhat-linux-gnu). Ошибка есть -bash: [: -v: unary operator expected. За комментарий здесь , он требует при минимальном Баше 4.2 работать.
Acumenus
Спасибо за проверку, когда она стала доступной. Я использовал его раньше в разных системах, но потом вдруг это не сработало. Я пришел сюда из любопытства и да, конечно, bash в этой системе - 3.x bash.
не пролить этот байк еще дальше, но хотелось добавить
shopt -s -o nounset
это то, что вы можете добавить в начало скрипта, что приведет к ошибке, если переменные нигде не объявлены в скрипте. Сообщение, которое вы увидите unbound variable, но, как другие отмечают, не будет содержать пустую строку или нулевое значение. Чтобы убедиться, что любое отдельное значение не пустое, мы можем протестировать переменную по мере ее расширения ${mystr:?}, также известную как расширение знака доллара, с которой произошла бы ошибка parameter null or not set.
Это может быть применено, выбирая соответствующие строки визуально, затем печатая :. Панель команд предварительно заполняется :'<,'>. Вставьте указанную выше команду и нажмите Enter.
Протестировано на этой версии Vim:
VIM -ViIMproved7.3(2010Aug15, compiled Aug22201515:38:58)Compiled by root@apple.com
Пользователи Windows могут захотеть разные окончания строк.
Написание функции не плохая идея; вызывать grepэто ужасно. Обратите внимание, что bashподдерживается ${!var_name}как способ получения значения переменной, имя которой указано в $var_name, так что name=value; value=1; echo ${name} ${!name}дает value 1.
Джонатан Леффлер
0
Более короткая версия для проверки неопределенной переменной может быть просто:
вызовите набор без каких-либо аргументов ... он выводит все определенные переменные ...
последними в списке будут те, которые определены в вашем скрипте ...
чтобы вы могли направить его вывод во что-то, что могло бы выяснить, какие вещи определены, а какие нет
[ -n "${VAR+x}"] && echo not null
[ -z ]
вместо[ -z "" ]
; если у него есть пробелы, он становится[ -z "my" "test" ]
вместо[ -z my test ]
; и если это так[ -z * ]
, то имя*
заменяется именами файлов в вашем каталоге.Ответы:
Я думаю , что ответ вы после Подразумевается (если не указано иное) на Винко «s ответ , хотя это не прописано просто. Чтобы определить, установлен ли VAR, но не указан или нет, вы можете использовать:
Вероятно, вы можете объединить два теста во второй строке в один с помощью:
Однако, если вы прочитаете документацию для Autoconf, вы обнаружите, что они не рекомендуют объединять термины с '
-a
' и рекомендуют использовать отдельные простые тесты в сочетании с&&
. Я не сталкивался с системой, где есть проблема; это не значит, что они не существовали (но они, вероятно, чрезвычайно редки в наши дни, даже если они не были такими редкими в далеком прошлом).Вы можете найти подробности об этих и других связанных расширениях параметров оболочки , командах
test
или[
условных выражениях или в руководстве по Bash.Меня недавно спросили по электронной почте об этом ответе с вопросом:
Справедливый вопрос - ответ «Нет, ваша простая альтернатива не делает то же самое».
Предположим, я напишу это перед тестом:
Ваш тест скажет «VAR вообще не установлен», но мой скажет (косвенно, потому что он ничего не повторяет) «VAR установлен, но его значение может быть пустым». Попробуйте этот скрипт:
Выход:
Во второй паре тестов переменная установлена, но ей присвоено пустое значение. Это различие, которое делают обозначения
${VAR=value}
и${VAR:=value}
. То же самое для${VAR-value}
и${VAR:-value}
, и${VAR+value}
и${VAR:+value}
, и так далее.Как указывает в своем ответе Гили , если вы запускаете с опцией, то основной ответ выше не с . Это легко исправить:
bash
set -o nounset
unbound variable
Или вы можете отменить
set -o nounset
опцию с помощьюset +u
(set -u
эквивалентноset -o nounset
).источник
${+}
и${-}
неясно, но знакомство с этими конструкциями необходимо для того, чтобы быть компетентным пользователем оболочки.set -o nounset
включенным.[ -v VAR ]
" подход с bash -s v4.2 и выше .-z работает и для неопределенных переменных. Чтобы различать неопределенное и определенное, вы должны использовать перечисленные здесь вещи или, с более понятными объяснениями, здесь .
Самый чистый способ - использовать расширение, как в этих примерах. Чтобы получить все ваши варианты, обратитесь к разделу «Расширение параметров» в руководстве.
Альтернативное слово:
Значение по умолчанию:
Конечно, вы бы использовали один из них по-другому, поместив желаемое значение вместо «значение по умолчанию» и используя расширение, если это необходимо.
источник
Расширенное руководство по написанию сценариев, 10.2. Подстановка параметров:
Чтобы основать логику вашей программы на том, определена переменная $ mystr или нет, вы можете сделать следующее:
теперь, если isdefined = 0, тогда переменная была неопределенной, если isdefined = 1, переменная была определена
Этот способ проверки переменных лучше, чем приведенный выше ответ, поскольку он более элегантен, удобочитаем, и если ваша оболочка bash была настроена на ошибку при использовании неопределенных переменных
(set -u)
, сценарий завершится преждевременно.Другие полезные вещи:
иметь значение по умолчанию 7, присвоенное $ mystr, если оно не было определено, и оставить его нетронутым в противном случае:
распечатать сообщение об ошибке и выйти из функции, если переменная не определена:
Остерегайтесь здесь того, что я использовал ':', чтобы содержимое $ mystr не выполнялось как команда, если оно определено.
источник
var= ; varname=var ; : ${!varname?not defined}
и это заканчивается:varname=var ; : ${!varname?not defined}
. Но это хорошая привычка,set -u
которая делает то же самое намного проще.Краткое содержание тестов.
источник
${var+x}
что в этом нет необходимости, за исключением случаев, когда имена переменных могут содержать пробелы.[
чтобы получить правильные результаты. Еслиvar
не установлено или пусто,[ -n $var ]
сводится к тому,[ -n ]
что имеет выходной статус 0, а[ -n "$var" ]
ожидаемый (и правильный) выходной статусhttps://stackoverflow.com/a/9824943/14731 содержит лучший ответ (который более читабелен и работает с
set -o nounset
включенным). Это работает примерно так:источник
Явным способом проверки определяемой переменной будет:
источник
test
оператор в хвостовой части раздела Bourne Shell Builtins . Я не знаю, когда он был добавлен, но его нет в версии Applebash
(основанной наbash
3.2.51), так что это, вероятно, функция 4.x.GNU bash, version 4.1.2(1)-release (x86_64-redhat-linux-gnu)
. Ошибка есть-bash: [: -v: unary operator expected
. За комментарий здесь , он требует при минимальном Баше 4.2 работать.другой вариант: расширение "список массивов индексов" :
единственный раз, когда это расширяется до пустой строки, это когда
foo
не установлено, так что вы можете проверить это с помощью условной строки:должен быть доступен в любой версии bash> = 3.0
источник
не пролить этот байк еще дальше, но хотелось добавить
это то, что вы можете добавить в начало скрипта, что приведет к ошибке, если переменные нигде не объявлены в скрипте. Сообщение, которое вы увидите
unbound variable
, но, как другие отмечают, не будет содержать пустую строку или нулевое значение. Чтобы убедиться, что любое отдельное значение не пустое, мы можем протестировать переменную по мере ее расширения${mystr:?}
, также известную как расширение знака доллара, с которой произошла бы ошибкаparameter null or not set
.источник
Bash Reference Manual является авторитетным источником информации о Баше.
Вот пример тестирования переменной, чтобы увидеть, существует ли она:
(Из раздела 6.3.2 .)
Обратите внимание, что пробел после открытия
[
и перед не]
является необязательным .Советы для пользователей Vim
У меня был скрипт, который имел несколько объявлений следующим образом:
Но я хотел, чтобы они подчинялись любым существующим ценностям. Поэтому я переписал их, чтобы они выглядели так:
Я смог автоматизировать это в VIM с помощью быстрого регулярного выражения:
Это может быть применено, выбирая соответствующие строки визуально, затем печатая
:
. Панель команд предварительно заполняется:'<,'>
. Вставьте указанную выше команду и нажмите Enter.Протестировано на этой версии Vim:
Пользователи Windows могут захотеть разные окончания строк.
источник
Вот то, что я думаю, является намного более ясным способом проверить, определена ли переменная:
Используйте это следующим образом:
источник
grep
это ужасно. Обратите внимание, чтоbash
поддерживается${!var_name}
как способ получения значения переменной, имя которой указано в$var_name
, так чтоname=value; value=1; echo ${name} ${!name}
даетvalue 1
.Более короткая версия для проверки неопределенной переменной может быть просто:
источник
вызовите набор без каких-либо аргументов ... он выводит все определенные переменные ...
последними в списке будут те, которые определены в вашем скрипте ...
чтобы вы могли направить его вывод во что-то, что могло бы выяснить, какие вещи определены, а какие нет
источник