Я знаю, что могу проверить пустую строку в Bash с помощью -z
следующим образом:
if [[ -z $myvar ]]; then do_stuff; fi
но я вижу много кода, написанного как:
if [[ X"" = X"$myvar" ]]; then do_stuff; fi
Является ли этот метод более переносимым? Является ли это просто историческим крушением до дней -z
? Это для оболочек POSIX (хотя я видел, что он использовался в таргетинге на сценарии bash
)? Готов к моему уроку истории/переносимости.
Тот же вопрос задавался на сервере Fault как Как определить, является ли переменная Bash пустой?, но никто не предложил объяснения, почему вы видите код с материалом X""
.
Ответ 1
В принципе, поскольку в те времена, когда давно прошло, поведение test
было более сложным и неравномерно определенным в разных системах (поэтому переносимый код должен был быть написан тщательно, чтобы избежать не переносных конструкций).
В частности, перед тем, как test
был встроенным оболочкой, он был отдельным исполняемым файлом (и обратите внимание, что в MacOS X все еще есть /bin/test
и /bin/[
в качестве исполняемых файлов). Когда это было так, напишите:
if [ -z $variable ]
когда $variable
был пустым, вызывал бы тестовую программу через свой псевдоним [
с тремя аргументами:
argv[0] = "["
argv[1] = "-z"
argv[2] = "]"
потому что переменная была пустой, поэтому нечего было расширять. Таким образом, безопасный способ написания кода:
if [ -z "$variable" ]
Это работает надежно, передавая 4 аргумента в исполняемый файл test
. Разумеется, тестовая программа была встроена в большинство оболочек на протяжении десятилетий, но старое оборудование сильно угасает, и поэтому хорошие практики изучаются еще более давно.
Другая проблема, разрешенная префиксом X, - это то, что произошло, если переменные включают в себя ведущие тире или содержат равные или другие компараторы. Рассмотрим (не совсем хороший пример):
x="-z"
if [ $x -eq 0 ]
Является ли это пустым строковым тестом с ошибочным (ошибочным) аргументом или методом числового равенства с нечисловым первым аргументом? Различные системы предоставляли разные ответы до того, как POSIX стандартизировала поведение примерно в 1990 году. Таким образом, безопасный способ борьбы с этим был:
if [ "X$x" = "X0" ]
или (менее обычно, по моему опыту, но полностью эквивалентно):
if [ X"$x" = X"0" ]
Это были все краевые случаи, подобные этому, связанный с возможностью того, что тест был отдельным исполняемым файлом, а это означает, что переносимый код оболочки по-прежнему использует двойные кавычки более обильно, чем на самом деле требуют современные оболочки, а нотация X-prefix был использован для обеспечения того, чтобы вещи не могли быть истолкованы неверно.
Ответ 2
А, это один из моих предпочтительных вопросов и ответов, потому что я придумал ответ, просто подумав об этом. X
устанавливается на всякий случай, когда строка начинается с -
, которую можно принять за флаг для теста. Поместите X
, прежде чем просто удалите этот случай, и сравнение все еще может быть выполнено.
Мне также нравится это, потому что этот трюк почти наследуется от прошлого, самых старых вычислений, и вы сталкиваетесь с ним, когда пытаетесь прочитать некоторые из самых переносимых сценариев оболочки там (autoconf, configure и т.д. )