Qual é a diferença entre sinais de igual simples e duplo (=) nas comparações de shell?


28

Leia que, para comparar cadeias internas if, precisamos usar colchetes duplos. Alguns livros dizem que a comparação pode ser feita por =. Mas funciona com o ==também.

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

Existe uma diferença entre =e ==na comparação?


4
Há alguma pergunta aqui em algum lugar? Se sim, não estou vendo. =é para [. ==é para [[.
Chris Baixo

@ ChrisDown Isso absolutamente não é verdade.
xdavidliu 30/11

@xdavidliu Gostaria de elaborar? Certamente é verdade de acordo com o POSIX, que não entende ==, e é por isso que você deve usar =(igualdade) com [e ==(correspondência de padrão, com semântica que cita) com [[. Veja help testvs help [[.
Chris Down

@ ChrisDown Talvez eu esteja entendendo mal o que se entende por "é para". Se "é para" significa "apenas funciona com", o comentário não é verdadeiro, pois [ foo == foo ] && echo foocertamente imprime foo, indicando que ==funciona com [. No entanto, se por "é para" você quer dizer "foi planejado para ser usado com", então eu tenho uma objeção menor.
xdavidliu 2/12

@xdavidliu "é para" no caso específico que você está mencionando, significa "é definido pelo POSIX". Só porque o bash o aceita como conveniência, não significa que seja recomendado - se você está evitando a portabilidade de qualquer maneira, basta usar [[em primeiro lugar o que possui uma compreensão significativamente mais sutil de tokenização, divisão de palavras, etc.
Chris Down

Respostas:


28

[[ $a == $b ]]não é comparação, é correspondência de padrões. Você precisa [[ $a == "$b" ]]fazer uma comparação de igualdade de bytes a bytes. =é o mesmo que ==em qualquer shell que suporte [[...]](introduzido por ksh).

[[...]]não é uma shsintaxe padrão . O [ comando é padrão e o operador de comparação padrão existe =(embora algumas [implementações também reconheçam ==).

Assim como em qualquer argumento de qualquer comando, as variáveis ​​devem ser citadas, portanto:

[ "$a" = "$b" ]

No padrão sh, a correspondência de padrões é feita com case:

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

Para garantir a integridade, outros operadores semelhantes à igualdade que você pode encontrar em scripts de shell:

  • [ "$a" -eq "$b" ]: [operador padrão para comparar números inteiros decimais. Algumas [implementações permitem espaços em branco em torno dos números, outras permitem expressões aritméticas arbitrárias, mas isso não é portátil. Portably, pode-se usar [ "$((a))" -eq "$((b))" ]para isso. Veja também [ "$((a == b))" -ne 0 ]qual seria o equivalente padrão (exceto que POSIXly, o comportamento é especificado apenas se $ae $bcontém constantes inteiras) de:
  • ((a == b)), de ksh e também encontrado em zshand bash, retorna true se a avaliação da expressão aritmética armazenada em $aproduzir o mesmo número que o de $b. Normalmente, isso é usado para comparar números. Observe que há variações entre os shells sobre como as expressões aritméticas são avaliadas e quais números são suportados (por exemplo, bash e algumas implementações / versões do ksh não suportam ponto flutuante ou tratam números com zeros à esquerda como octais).

  • expr "$a" = "$b"faz uma comparação numérica se os dois operandos são reconhecidos como números inteiros decimais (alguns permitem espaços em branco ao redor do número) e, de outra forma, verifica se os dois operadores de sequência têm a mesma ordem de classificação. Também falharia com valores de $aou $bque são exproperadores como (, substr...

  • awk 'BEGIN{exit !(ARGV[1] == ARGV[2])}' "$a" "$b": se $ae $bsão reconhecidos como números (pelo menos números inteiros decimais e números de ponto flutuante como 1,2, -1,5e-4, espaços em branco à esquerda ignorados, alguns também reconhecendo hexadecimal, octal ou qualquer coisa reconhecida por strtod()), então é realizada uma comparação numérica. Caso contrário, dependendo da implementação, é uma comparação de cadeias de bytes a bytes ou como para expruma strcoll()comparação, que é a mesma $ae se é ou não $ba mesma.

Veja também:


13

Estes são equivalentes no bash:

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

As duas primeiras variáveis ​​$ x não precisam ser citadas. O Bash realiza a divisão de palavras e a expansão do nome do caminho dentro [mas não dentro [[:

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

[[ $x = "$y" ]]é uma comparação de cadeias, mas [[ $x = $y ]]é uma expressão correspondente a padrão:

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

-eq deve ser usado apenas com números inteiros:

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

Veja também BashFAQ / 031: Qual é a diferença entre test, [e [[? .

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.