В чем разница между одинарным и двойным знаком равенства (=) в сравнениях оболочки?

28

Прочитайте, что для сравнения строк внутри ifмы должны использовать двойные квадратные скобки. В некоторых книгах говорится, что сравнение может быть сделано =. Но это работает с ==тоже.

#!/bin/bash
a="hello"
b="world"
if [[ $a == $b ]];then
    echo "equal"
fi

Есть ли разница между =и ==в сравнении?

user3539
источник
4
Здесь есть вопрос? Если так, я этого не вижу. =для [. ==для [[.
Крис Даун
@ChrisDown Это абсолютно не так.
xdavidliu
@xdavidliu Хотите разработать? Это, безусловно , верно в соответствии с POSIX, который не имеет представления о том ==, почему вы должны использовать =(равенство) с [и ==(сопоставление с образцом с семантикой, поддерживающей цитирование) с [[. См help testпротив help [[.
Крис Даун
@ChrisDown, может быть, я неправильно понимаю, что означает «для». Если «для» означает «работает только с», то комментарий не соответствует действительности, поскольку, [ foo == foo ] && echo fooбезусловно, печатает foo, указывая, что ==работает с [. Тем не менее, если под «это означает» вы подразумеваете «был предназначен для использования с», то у меня меньше возражений.
xdavidliu
@xdavidliu "для" в конкретном случае, который вы упоминаете, означает "определяется POSIX". [[Тот факт, что bash воспринимает это как удобство, не означает, что он рекомендуется - если вы все-таки отказываетесь от переносимости, просто используйте во-первых, у которого значительно более детальное понимание токенизации, разбиения слов и т. Д.
Крис Даун

Ответы:

28

[[ $a == $b ]]это не сравнение, это сопоставление с образцом. Вам нужно [[ $a == "$b" ]]сравнить байтовое равенство. =такой же, как и ==в любой поддерживаемой оболочке [[...]](представленной ksh).

[[...]]это не стандартный shсинтаксис. [ Команда является стандартной, и стандартным сравнением оператора есть =(хотя некоторые [реализации также признают ==).

Как и в любом аргументе любой команды, переменные должны быть заключены в кавычки, поэтому:

[ "$a" = "$b" ]

В стандарте shсопоставление с образцом выполняется с помощью case:

case $a in
  ($b) ...
esac

Для полноты, другие похожие на равенство операторы вы можете встретить в сценариях оболочки:

  • [ "$a" -eq "$b" ]: стандартный [оператор для сравнения десятичных целых чисел. Некоторые [реализации допускают пробелы вокруг чисел, некоторые допускают произвольные арифметические выражения, но это не переносимо. Портативно, можно использовать [ "$((a))" -eq "$((b))" ]для этого. Смотрите также, [ "$((a == b))" -ne 0 ]какой будет стандартный эквивалент (за исключением того, что POSIXly, поведение указывается, только если $aи $bсодержат целочисленные константы) из:
  • ((a == b)), из ksh и также найденный в zshи bash, возвращает true, если оценка арифметического выражения, сохраненного в, $aдает то же число, что и у $b. Как правило, это используется для сравнения чисел. Обратите внимание, что между оболочками существуют различия в том, как оцениваются арифметические выражения и какие числа поддерживаются (например, bash и некоторые реализации / версии ksh не поддерживают числа с плавающей запятой или обрабатывают числа с ведущими нулями как восьмеричные).

  • expr "$a" = "$b"выполняет сравнение чисел, если оба операнда распознаются как десятичные целые числа (некоторые допускают пропуски вокруг числа), и в противном случае проверяет, имеют ли два строковых оператора одинаковый порядок сортировки. Это также не удалось бы для значений $aили $bтаких exprоператоров, как (, substr...

  • awk 'BEGIN{exit !(ARGV[1] == ARGV[2])}' "$a" "$b": если $aи $bраспознаются как числа (по крайней мере десятичное целое число и числа с плавающей запятой, такие как 1.2, -1.5e-4, начальные конечные пробелы игнорируются, некоторые также распознают шестнадцатеричное, восьмеричное или что-либо еще, распознаваемое strtod()), то выполняется числовое сравнение. В противном случае, в зависимости от реализации, это либо байт в байт сравнение строк, или как для exprболее strcoll()сравнения, то есть ли $aи $bвроде то же самое.

Смотрите также:

Стефан Шазелас
источник
13

Это эквивалентно в bash:

[[ $x == "$y" ]]
[[ $x = "$y" ]]
[ "$x" == "$y" ]
[ "$x" = "$y" ]

Первые две переменные $ x не нужно заключать в кавычки. Bash выполняет разбиение слов и расширение пути внутри [но не внутри [[:

$ x='a b'
$ [ -s $x ]
-bash: [: a: binary operator expected
$ [[ -s $x ]]
$ ls
$ [ a = * ]
-bash: [: a: unary operator expected
$ [[ a = * ]]
$ 

[[ $x = "$y" ]]это сравнение строк, но [[ $x = $y ]]это выражение соответствия шаблону:

$ y='a*'; [[ aa = "$y" ]]; echo $?
1
$ y='a*'; [[ aa = $y ]]; echo $?
0

-eq предназначен только для использования с целыми числами:

$ [[ x.x -eq x.x ]]
-bash: [[: x.x: syntax error: invalid arithmetic operator (error token is ".x")
$ x=9; [[ "x" -eq 9 ]]; echo $?
0

См. Также BashFAQ / 031: В чем разница между тестом [и [[? ,

LRI
источник