Цель добавления префикса на обеих сторонах сравнения переменных оболочки с литералом строки?

ip link show отображает флаг «LOWER_UP», чтобы указать, что кабель подключен. Вы также можете проверить / sys / class / net / eth * / operstate или carrier. Однако все это работает только для интерфейса с привязанным к нему IP-адресом.

4
21.12.2018, 22:54
2 ответа

Здесь важно понимать, что в большинстве оболочек¹ [— это обычная команда, анализируемая оболочкой, как и любая другая обычная команда.

Затем оболочка вызывает команду [(, также известную как test), со списком аргументов, после чего [интерпретирует их как условное выражение.

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

Утилита [раньше с трудом определяла, какие из ее аргументов были операторами, а какие операндами, (с которыми работают операторы ). Не помогло и то, что синтаксис изначально был двусмысленным. Например:

  • [ -t ]раньше был (и до сих пор присутствует в некоторых оболочках/ [s )для проверки того, является ли стандартный вывод терминалом.
  • [ x ]является сокращением от[ -n x ]:проверить, является ли xне -пустой строкой (, поэтому вы можете увидеть конфликт с приведенным выше ).
  • в некоторых оболочках/ [s, -aи -oмогут быть унарными([ -a file ]для доступный файл(теперь заменен на [ -e file ]), [ -o option ]для опция включена?)и бинарные операторы(и и или). Опять же, ! -a xможет быть либо and(nonempty("!"), nonempty("x")), либо not(isaccessible("x")).
  • (, )и !добавляют больше проблем.

В обычных языках программирования, таких как C или perl, в:

if ($a eq $b) {...}

Содержимое $aили $bникоим образом не будет восприниматься как операторы, поскольку условное выражение анализируется до того, как $aи $bрасширяются. Но в снарядах, в:

[ "$a" = "$b" ]

Оболочка расширяет переменные сначала ². Например, если $aсодержит (, а $bсодержит ), все, что видит команда [, это [, (, =,)и ]аргументы. Значит ли это, что"(" = ")"(являются (и )лексически равными )или( -n = )(является =не -пустой строкой ).

Исторические реализации(testпоявились в Unix V7 в конце 70-х годов )раньше давали сбой даже в тех случаях, когда это не было неоднозначно только из-за порядка, в котором они обрабатывали свои аргументы.

Здесь с версией 7 Unix в эмуляторе PDP11:

$ ls -l /bin/[
-rwxr-xr-x 2 bin      2876 Jun  8  1979 /bin/[
$ [ ! = x ]
test: argument expected
$ [ "(" = x ]
test: argument expected

Большинство оболочек и [реализаций имеют или имели проблемы с ними или их вариантами . С bash4.4 сегодня:

bash-4.4$ a='(' b=-o c=x
bash-4.4$ [ "$a" = "$b" -o "$a" = "$c" ]
bash: [: `)' expected, found =

POSIX.2 (, опубликованный в начале 90-х ), разработал алгоритм , который сделает поведение [однозначным и детерминированным при передаче не более 4 аргументов (рядом с [и])в наиболее распространенных шаблонах использования ([ -f "$a" -o "$b" ], которые еще не указаны, например, ). Он устарел (, ), -aи -oи удалил -tбез операнда. bashреализовал этот алгоритм (или, по крайней мере, попытался )в bash2.0.

Таким образом, в POSIX-совместимых реализациях [[ "$a" = "$b" ]гарантированно сравнивает содержимое $aи $bна предмет равенства, какими бы они ни были. Без -oмы бы написали:

[ "$a" = "$b" ] || [ "$a" = "$c" ]

То есть вызовите [дважды, каждый раз с менее чем 5 аргументами.

Но потребовалось некоторое время, чтобы все [реализации стали совместимыми. bashне был совместим до 4.4 (, хотя последняя проблема была для [ '(' ! "$var" ')' ], которую никто не использовал в реальной жизни)

Оболочка /bin/shSolaris 10 и старше, которая не является оболочкой POSIX, а является оболочкой Bourne, по-прежнему имеет проблемы с[ "$a" = "$b" ]:

$ a='!' b='!'
$ [ "$a" = "$b" ]
test: argument expected

Использование [ "x$a" = "x$b" ]решает проблему, поскольку нет оператора [, который начинается с x. Другой вариант — использовать caseвместо :

.
case "$a" in
  "$b") echo same;;
     *) echo different;;
esac

(цитирование необходимо вокруг $b, а не вокруг$a).

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

$ a= b='-o x'
[ $a = $b ]

со значением по умолчанию $IFSстановится:

[ = -o x ]

Это проверка того, является ли =или xнепустой строкой -, но никакие префиксы не помогут³, так как [ x$a = x$b ]по-прежнему будет :[ x = x-o x ], что вызовет ошибку, и это может стать намного хуже, включая DoS и ввод произвольной команды с другими значениями, как вbash:

bash-4.4$ a= b='x -o -v a[`uname>&2`]'
bash-4.4$ [ x$a = x$b ]
Linux

Правильным решением будет всегда цитировать:

[ "$a" = "$b" ]   # OK in POSIX compliant [ / shells
[ "x$a" = "x$b" ] # OK in all Bourne-like shells

Обратите внимание, что exprимеет аналогичные (и даже более серьезные )проблемы.

exprтакже имеет оператор =, хотя он предназначен для проверки того, являются ли два операнда равными целыми числами, когда они выглядят как десятичные целые числа, или сортируются одинаково, если нет.

Во многих реализациях expr + = +, expr '(' = ')'или expr index = indexне выполняют сравнение на равенство. expr "x$a" = "x$b"может обойти это для сравнения строк, но префикс xможет повлиять на сортировку (в локалях, которые имеют элементы сортировки, начинающиеся с x, например ), и, очевидно, не могут использоваться для числа сравнение expr "0$a" = "0$b"не работает для сравнения отрицательных целых чисел. expr " $a" = " $b"работает для целочисленного сравнения в некоторых реализациях, но не в других (для a=01 b=1, некоторые вернут true, некоторые false ).


¹ ksh93является исключением. В ksh93[можно рассматривать как зарезервированное слово, поскольку [ -t ]на самом деле отличается от var=-t; [ "$var" ]или от ""[ -t ]или cmd='['; "$cmd" -t ]. Это сделано для того, чтобы сохранить обратную совместимость и по-прежнему соответствовать POSIX в тех случаях, когда это имеет значение. Здесь -tвоспринимается как оператор только в том случае, если он буквальный, а ksh93определяет, что вы вызываете команду [.

² ksh добавил [[...]]оператор условного выражения с собственными правилами разбора синтаксиса (и некоторыми собственными проблемами )для решения проблем, которые (также встречаются в некоторых других оболочках, с некоторыми отличиями ).

³ за исключением zsh, где split+glob не вызывается при расширении параметра, но пустое удаление по-прежнему вызывается, или в других оболочках при глобальном отключении split+glob с помощьюset -o noglob; IFS=

15
27.01.2020, 20:46

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

Недавние реализации команды на большинстве платформ избегают ловушки с просмотром -вперед в синтаксическом анализаторе выражений, не позволяя синтаксическому анализатору распознавать первый операнд бинарного оператора как что-либо, кроме операнда, до тех пор, пока имеется достаточно tokens to быть бинарным оператором, конечно:

% a=-n
% /bin/test "$a" = -n ; echo $?
0
% /bin/test "$a" = ; echo $?
0
% /bin/test x"$a" = ; echo $?
test: =: argument expected
2
% a='('
% /bin/test "$a" = "(" ; echo $?
0
% /bin/test "$a" = ; echo $?
test: closing paren expected
2
%
7
27.01.2020, 20:46

Теги

Похожие вопросы