Подтвердить что ты не робот

Почему в shell script часто используются x $VAR = xyes?

Я часто вижу это в сценариях сборки проектов, использующих autotools (autoconf, automake). Когда кто-то хочет проверить значение переменной оболочки, они часто используют эту идиому:

if test "x$SHELL_VAR" = "xyes"; then
...

В чем преимущество этого, просто проверяя значение, подобное этому:

if test $SHELL_VAR = "yes"; then
...

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

4b9b3361

Ответ 1

Если вы используете оболочку, которая выполняет простую подстановку, а переменная SHELL_VAR не существует (или является пустой), то вам нужно следить за крайними случаями. Произойдут следующие переводы:

if test $SHELL_VAR = yes; then        -->  if test = yes; then
if test x$SHELL_VAR = xyes; then      -->  if test x = xyes; then

Первое из них приведет к ошибке, поскольку первый аргумент test пропал. Второй не имеет этой проблемы.

Ваш случай переводится следующим образом:

if test "x$SHELL_VAR" = "xyes"; then  -->  if test "x" = "xyes"; then

x, по крайней мере для POSIX-совместимых оболочек, на самом деле является избыточным, поскольку из кавычек следует, что как пустой аргумент, так и один содержащий пробелы интерпретируются как один объект.

Ответ 2

Другая причина, о которой еще никто не упомянул, касается обработки опций. Если вы пишете:

if [ "$1" = "abc" ]; then ...

и $1 имеет значение '-n', синтаксис тестовой команды неоднозначен; неясно, что вы тестировали. "X" на передней панели предотвращает возникновение проблем с ведущим тире.

Вы должны смотреть на действительно древние раковины, чтобы найти ту, где тестовая команда не поддерживает -n или -z; команда Версии 7 (1978) test включила их. Это не совсем неуместно - некоторые версии UNIX версии 6 ускользнули в BSD, но в наши дни вам будет крайне сложно найти что-нибудь древнее в текущем использовании.

Не использование двойных кавычек вокруг значений опасно, как указывал ряд других людей. В самом деле, если есть вероятность, что имена файлов могут содержать пробелы (MacOS X и Windows в любом случае поощряют это, и Unix всегда поддерживала его, хотя инструменты, такие как xargs, усложняют), тогда вы должны заключать имена файлов в двойные цитирует каждый раз, когда вы их используете. Если вы не отвечаете за значение (например, во время обработки параметров, и вы устанавливаете переменную "нет" при запуске и "да", когда флаг включен в командную строку), небезопасно использовать некотируемые формы переменных пока вы не докажете их в безопасности - и вы также можете делать это все время для многих целей. Или документ о том, что ваши скрипты будут терпеть неудачу, если пользователи попытаются обработать файлы с пробелами в именах. (И есть и другие персонажи, о которых можно беспокоиться - например, backticks может быть довольно неприятным.)

Ответ 3

Есть две причины, по которым я знаю это соглашение:

http://tldp.org/LDP/abs/html/comparison-ops.html

В сложном тесте даже цитирование строковой переменной может оказаться недостаточным. [-n "$ string" -o "$ a" = "$ b" ] может привести к ошибке с некоторыми версиями Bash, если $string пуст. Безопасный способ - добавить дополнительный символ в возможно, пустые переменные, [ "x $string"!= x -o "x $a" = "x $b" ] ( "x's" отменяется).

Во-вторых, в других оболочках, чем Bash, особенно более старые, условия теста, такие как '-z' для проверки пустой переменной, не существовали, поэтому, если это:

if [ -z "$SOME_VAR" ]; then
  echo "this variable is not defined"
fi

будет работать отлично в Bash, если вы нацелены на переносимость в различных средах UNIX, где вы не можете быть уверены, что оболочка по умолчанию будет Bash и поддерживает ли она условие -z test, это безопаснее использовать форму, если [ "x $SOME_VAR" = "x" ], поскольку это всегда будет иметь предполагаемый эффект. По сути, это старый трюк для сценариев для поиска пустой переменной, и он по-прежнему используется сегодня для обратной совместимости, несмотря на наличие доступных доступных методов.

Ответ 4

Вместо этого я рекомендую:

if test "yes" = "$SHELL_VAR"; then

поскольку он устраняет уродливый x и по-прежнему решает проблему, упомянутую fooobar.com/questions/134219/..., что $SHELL_VAR может начинаться с - и быть читать как вариант.

Ответ 5

Я считаю, что благодаря

SHELLVAR=$(true)
if test $SHELLVAR  = "yes" ; then echo "yep" ; fi 

# bash: test: =: unary operator expected

а также

if test $UNDEFINEDED = "yes" ; then echo "yep" ; fi
# bash: test: =: unary operator expected

и

SHELLVAR=" hello" 
if test $SHELLVAR = "hello" ; then echo "yep" ; fi
# yep 

однако это обычно должно работать

SHELLVAR=" hello"
if test "$SHELLVAR" = "hello" ; then echo "yep" ; fi 
#<no output>

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

SHELLVAR=" hello"
if test "x$SHELLVAR" = "xhello" ; then echo "yep" ; fi 

работает так же хорошо, но будет легче отлаживать.

Ответ 6

Я использовал это в DOS, когда SHELL_VAR может быть undefined.

Ответ 7

Если вы не делаете "x $SHELL_VAR", то если $SHELL_VAR undefined, вы получите сообщение об ошибке "=", не являющемся монадическим оператором или чем-то вроде этого.