Por que o `==` se comporta de maneira diferente dentro do `[…]` no zsh e no bash?

9

Eu recebo o que esperava ao fazer isso em bash:

[ "a" == "a" ] && echo yes

Isso me deu yes.

Mas quando faço isso zsh, recebo o seguinte:

zsh: = not found

Por que o mesmo comando ( /usr/bin/[) se comporta de maneira diferente em diferentes shells?

Johnson Steward
fonte
5
não é o mesmo comando - é um builtin encontrado antes da $PATHpesquisa. e ==não é uma testsintaxe válida para a /usr/bin/[rota. Apenas =está bem.
mikeserv

Respostas:

18

Não está /usr/bin/[em nenhuma das conchas. Em Bash, você está usando o built-in test/ [comando , e de forma semelhante em zsh .

A diferença é que o zsh também tem uma =expansão : se =fooexpande para o caminho do fooexecutável. Isso significa que ==é tratado como tentar encontrar um comando chamado =no seuPATH . Como esse comando não existe, você recebe o erro

zsh: = not found

que você viu (e, de fato, a mesma coisa aconteceria mesmo se você estivesse usando /usr/bin/[).


Você pode usar ==aqui se você realmente quiser. Isso funciona como o esperado no zsh:

[ "a" "==" "a" ] && echo yes

porque a citação impede a =wordexpansão em execução. Você também pode desativar a equalsopção com setopt noequals.


No entanto, você estaria melhor:

  • Usando single =, o teste de igualdade compatível com POSIX ; ou
  • Melhor ainda, usando os [[condicionais com== no Bash e no zsh . Em geral, [[é apenas melhor e mais seguro, incluindo evitar esse tipo de problema (e outros) por ter regras especiais de análise.
Michael Homer
fonte
Qual é a diferença exata entre [e [[? (Pesquisando no Google [ vs [[me dá resultados para vssomente, LOL)
Johnson Steward
2
[[suporta uma ampla gama de testes nos dois casos e possui regras de análise personalizadas que evitam a necessidade de citar variáveis, operadores e assim por diante. Se você estiver usando especificamente o Bash ou o zsh, use [[. Se você estiver escrevendo um script portátil, escreva no comando [/ compatível com POSIX test(que pode ou não ser um comando real no sistema em execução).
Michael Homer
1
Basta usar [[lá e esquecer que [existe.
Michael Homer
1
você sabe ... eu discordo de sua recomendação. [[é diferentemente capaz. tente isso com ele: for f in *; do [ -e "$f" ] && for a in f d h p S b c; do [ "-$a" "$f" ] && for p in r w x u g; do [ "-$p" "$f" ] || p=-; a=$a$p; done && break; done && printf "%s:\t%s\n" "$a" "$f"; done.
mikeserv
3
Bem, =/ ==é sem dúvida um caso em que [[não é melhor do que [, como [[ a == b ]]é faz "a" coincidir com o "b" padrão e não é "a" igual a "b" como seria de esperar. Isso significa que você precisa escrever, [[ $a == "$b" ]]por exemplo. Pelo menos, com o [comando, se você souber como a análise de comandos funciona, você precisará escrevê-lo [ "$a" = "$b" ]para impedir o operador split + glob como em outros comandos. Com isso em mente e se você não usar -a ou -o, [é seguro nas implementações em conformidade com POSIX.
Stéphane Chazelas
2

E zsh e bash dão a mesma resposta (também typeestá embutida nos dois shells):

$ type -a [
[ is a shell builtin
[ is /usr/bin/[
Jshura
fonte
2

[ é um comando interno do shell no bash e no zsh:

$ type [
[ is a shell builtin

Na documentação dos comandos internos do shell :

Os comandos internos estão contidos no próprio shell . Quando o nome de um comando interno é usado como a primeira palavra de um comando simples (consulte Comandos Simples ), o shell executa o comando diretamente, sem chamar outro programa. Os comandos internos são necessários para implementar funcionalidades impossíveis ou inconvenientes de serem obtidas com utilitários separados.

A documentação oficial ( $ help test) permite apenas usar =:

STRING1 = STRING2

Verdadeiro se as strings forem iguais.

Portanto, a expressão correta seria:

$ [ "a" = "a" ] && echo yes
yes

O que acontece é que o bash é um pouco menos rigoroso. O suporte ao ==operador [ parece ser uma extensão do bash e não é recomendável usá-lo:

string1 == string2

string1 = string2

Verdadeiro se as strings forem iguais. Quando usado com o comando [[, ele executa a correspondência de padrões conforme descrito acima (consulte Construções Condicionais ).

'=' deve ser usado com o comando test para conformidade com POSIX.

Se você deseja usar ==, use a [[palavra-chave:

$ [[ "a" == "a" ]] && echo yes
yes

Lembre-se de que [[é menos portátil (não é POSIX). Mas tanto o bash quanto o zsh suportam.

zuazo
fonte
1

Nos dois shells, bashe zsh, o [utilitário é um shell embutido. Esta é a implementação de shells dessa ferramenta, que é usada preferencialmente ao binário /usr/bin/[. Os diferentes resultados encontrados são causados ​​por diferentes implementações.


Em bash, o [utilitário aceita CONDITIONAL EXPRESSIONScomo o [[comando composto. De acordo com a página do homem bashs tanto =e ==são válidos:

string1 == string2
string1 = string2
        True if the strings are equal.  = should be used with the test command for POSIX
        conformance.

Em zsh, o [utilitário tenta implementar o POSIX e suas extensões onde estas são especificadas. Na especificação do utilitário de teste POSIX, não há ==operador definido.

caos
fonte