Alguém pode explicar a diferença entre -eq
e ==
no script bash?
Existe alguma diferença entre os seguintes?
[ $a -eq $b ]
e [ $a == $b ]
Simplesmente isso ==
é usado apenas quando as variáveis contêm números?
Alguém pode explicar a diferença entre -eq
e ==
no script bash?
Existe alguma diferença entre os seguintes?
[ $a -eq $b ]
e [ $a == $b ]
Simplesmente isso ==
é usado apenas quando as variáveis contêm números?
Respostas:
É o contrário: =
e ==
para comparações de strings, -eq
é para numéricas. -eq
está na mesma família como -lt
, -le
, -gt
, -ge
, e -ne
, se isso ajuda a lembrar qual é qual.
==
é um bash-ismo, a propósito. É melhor usar o POSIX =
. No bash, os dois são equivalentes e, na planície, sh =
é o único com garantia de funcionamento.
$ a=foo
$ [ "$a" = foo ]; echo "$?" # POSIX sh
0
$ [ "$a" == foo ]; echo "$?" # bash specific
0
$ [ "$a" -eq foo ]; echo "$?" # wrong
-bash: [: foo: integer expression expected
2
(Observação: cite as expansões variáveis! Não deixe as aspas duplas acima.)
Se você estiver escrevendo um #!/bin/bash
roteiro, então eu recomendo usar [[
vez . A forma dobrada tem mais recursos, sintaxe mais natural e menos truques que o farão mal. As aspas duplas não são mais necessárias $a
, por exemplo:
$ [[ $a == foo ]]; echo "$?" # bash specific
0
Veja também:
[[ $var = $pattern ]]
, se você quer o que de outra forma seria interpretado como um padrão fnmatch em vez disso ser interpretada como uma string literal. A string foo
não tem interpretação não literal, deixando as aspas totalmente seguras; é apenas se o OP quiser corresponder, digamos foo*
(com o asterisco como literal, não significando nada que possa vir após a sequência foo
), que aspas ou escape serão necessários.
[[
sendo um basismo (indicando que esse era o único motivo pelo qual você não estava dando +1 na resposta).
[ ... ]
e duplo sinal de igual ==
. : - /
Depende da construção de teste em torno do operador. Suas opções são parênteses duplos, chaves duplas, chaves simples ou teste
Se você usa ((...)) , está testando a equidade aritmética com ==
C:
$ (( 1==1 )); echo $?
0
$ (( 1==2 )); echo $?
1
(Nota: 0
significa true
no sentido Unix e diferente de zero é um teste que falhou)
Usar -eq
dentro de parênteses duplos é um erro de sintaxe.
Se você estiver usando [...] (ou chaves simples) ou [...] [...] (ou chaves duplas), ou test
poderá usar um de -eq, -ne, -lt, -le, -gt ou -ge como uma comparação aritmética .
$ [ 1 -eq 1 ]; echo $?
0
$ [ 1 -eq 2 ]; echo $?
1
$ test 1 -eq 1; echo $?
0
O ==
interior de chaves simples ou duplas (ou test
comando) é um dos operadores de comparação de cadeias :
$ [[ "abc" == "abc" ]]; echo $?
0
$ [[ "abc" == "ABC" ]]; echo $?
1
Como operador de cadeia, =
é equivalente ==
e observe o espaço em branco ao redor =
ou ==
é obrigatório.
Enquanto você pode fazer [[ 1 == 1 ]]
ou [[ $(( 1+1 )) == 2 ]]
está testando a igualdade de cadeias - não a igualdade aritmética.
Portanto, -eq
produz o resultado provavelmente esperado que o valor inteiro de 1+1
seja igual a 2
, embora o RH seja uma string e tenha um espaço à direita:
$ [[ $(( 1+1 )) -eq "2 " ]]; echo $?
0
Enquanto uma comparação de cadeias de caracteres pega o espaço à direita e, portanto, a comparação de cadeias falha:
$ [[ $(( 1+1 )) == "2 " ]]; echo $?
1
E uma comparação incorreta de cadeias pode produzir a resposta errada completa. '10' é lexicograficamente menor que '2'; portanto, uma comparação de string retorna true
ou 0
. Muitos são mordidos por esse bug:
$ [[ 10 < 2 ]]; echo $?
0
vs o teste correto para 10 sendo aritmeticamente menor que 2:
$ [[ 10 -lt 2 ]]; echo $?
1
Nos comentários, há uma questão da razão técnica, usando o número inteiro -eq
em strings retorna True para strings que não são iguais:
$ [[ "yes" -eq "no" ]]; echo $?
0
O motivo é que o Bash não é digitado . Isso -eq
faz com que as seqüências sejam interpretadas como números inteiros, se possível, incluindo a conversão de base:
$ [[ "0x10" -eq 16 ]]; echo $?
0
$ [[ "010" -eq 8 ]]; echo $?
0
$ [[ "100" -eq 100 ]]; echo $?
0
E 0
se Bash achar que é apenas uma string:
$ [[ "yes" -eq 0 ]]; echo $?
0
$ [[ "yes" -eq 1 ]]; echo $?
1
Então [[ "yes" -eq "no" ]]
é equivalente a[[ 0 -eq 0 ]]
Última observação: muitas extensões específicas do Bash para as Construções de Teste não são POSIX e, portanto, falharão em outros shells. Outras conchas geralmente não suportam [[...]]
e ((...))
ou==
.
[[ "yes" -eq "no" ]]
retornar True. Como o bash coage essas strings a valores inteiros que podem ser comparados? ;-)
[[ "yes" -eq "no" ]]
são equivalentes a [[ "yes" -eq 0 ]]
ou [[ "yes" -eq "any_noninteger_string" ]]
- All True. A -eq
comparação de forças inteiras. O "yes"
é interpretado como um número inteiro 0
; a comparação é True se o outro número inteiro for um 0
ou o resultado da sequência 0
.
==
nos exemplos de código e apenas mencionando (portátil, padronizado) =
embaixo.
==
é um alias específico do bash =
e executa uma comparação de sequência (lexical) em vez de uma comparação numérica. eq
sendo uma comparação numérica, é claro.
Por fim, geralmente prefiro usar o formulário if [ "$a" == "$b" ]
==
aqui é uma forma incorreta, pois somente =
é especificado pelo POSIX.
==
-lo, coloque-o entre [[
e ]]
. (E certifique-se de que a primeira linha do seu script especifique o uso /bin/bash
).
Caras: Várias respostas mostram exemplos perigosos. O exemplo do OP [ $a == $b ]
usou especificamente a substituição de variáveis não citadas (a partir de outubro de 17). Pois [...]
isso é seguro para a igualdade de cadeias.
Mas se você enumerar alternativas como [[...]]
, deve informar também que o lado direito deve ser citado. Se não citado, é uma correspondência de padrão! (Na página de manual do bash: "Qualquer parte do padrão pode ser citada para forçá-lo a corresponder como uma string.").
Aqui no bash, as duas instruções que produzem "yes" correspondem a padrões, outras três são igualdade de cadeias:
$ rht="A*"
$ lft="AB"
$ [ $lft = $rht ] && echo yes
$ [ $lft == $rht ] && echo yes
$ [[ $lft = $rht ]] && echo yes
yes
$ [[ $lft == $rht ]] && echo yes
yes
$ [[ $lft == "$rht" ]] && echo yes
$
[ "$lht" = "$rht" ]
com as aspas para ser confiável, mesmo para a igualdade. Se você tiver criado um arquivo com touch 'Afoo -o AB'
, [ $lft = $rht ]
retornará true, mesmo que esse nome não seja idêntico a AB
.
[[
como um todo, é um ksh-ismo da década de 1980 que o bash (e muitas outras conchas) adotou. Esse é o ponto inteiro - se você tem[[
em tudo , então você pode seguramente assumir que todas as extensões ksh implementado em torno dele (fnmatch()
estilo de correspondência de padrões, ERE expressões regulares com=~
, e sim, a supressão da cadeia de divisão e sistema de arquivos englobamento) será acessível. Como a[[
sintaxe não é POSIX na sua totalidade, não há perda de portabilidade adicional ao assumir que os recursos com os quais ele nasceu estarão disponíveis.