Estou perplexo, mas ainda acho que não entendi Bash de alguma forma.
/$ if [ -e /bin/grep ]; then echo yea; else echo nay ; fi
yea
/$ if [ ! -e /bin/grep ]; then echo yea; else echo nay ; fi
nay
/$ if [ -a /bin/grep ]; then echo yea; else echo nay ; fi
yea
/$ if [ ! -a /bin/grep ]; then echo yea; else echo nay ; fi
yea
Por que a negação !
reverte o efeito do -e
teste, mas não -a
o teste?
Man bash disse:
teste :
3 argumentos
As condições a seguir são aplicadas na ordem listada.
- Se o segundo argumento for um dos operadores condicionais binários listados acima em EXPRESSÕES CONDICIONAIS, o resultado da expressão será o resultado do teste binário usando o primeiro e o terceiro argumentos como operandos. Os operadores
-a
e-o
são considerados operadores binários quando há três argumentos.- Se o primeiro argumento for
!
, o valor será a negação do teste de dois argumentos usando o segundo e o terceiro argumentos.
Expressões Condicionais Bash
Expressões condicionais são usadas pelo
[[
comando composto e pelos comandos internostest
e[
-a file
Verdadeiro se o arquivo existir.
-b file
True se o arquivo existir e for um arquivo especial de bloco.
-c file
True se o arquivo existir e for um arquivo especial de caracteres.
-d file
True se o arquivo existir e for um diretório.
-e file
Verdadeiro se o arquivo existir.
-a
é um operador unário (paraa
cessível, adicionado para compatibilidade com o shell Korn, mas fora do padrão e agora redundante com-e
) e binário (paraa
nd, em POSIX (com XSI), mas obsoleto lá).Aqui
[ ! -a /bin/grep ]
invoca o operador binário conforme exigido pelo POSIX. É[ "$a" -a "$b" ]
para testar se$a
não está vazio e$b
não está vazio, aqui com$a
==!
e$b
==/bin/grep
. Como ambas as strings não são vazias, ela retorna true .Veja também "Os operadores -a e -o são considerados operadores binários quando há três argumentos" no texto que você citou.
-a
está obsoleto tanto na forma unária quanto na forma binária, a unária porque é substituída por-e
, a binária porque cria expressões de teste não confiáveis e ambíguas.Para testar a existência do arquivo (embora, na verdade, seja mais um teste se o arquivo é acessível , se
stat()
seria bem-sucedido no caminho¹), use[ -e filepath ]
. Para e duas condições, use&&
entre duas invocações de[
.Para testar se uma string não está vazia, eu pessoalmente prefiro o
[ -n "$string" ]
formulário ao[ "$string" ]
outro.Então:
teste para a existência do arquivo:
teste para duas strings não vazias:
Da lógica na especificação POSIX para o utilitário
test
(aka[
) :e:
Os manuais do
yash
,bosh
, GNUcoreutils
protegem contra o uso de binário-a
/-o
em suas respectivas[
/test
implementações ezsh
o manual do ' nunca os documentou², mas muitos outros, incluindobash
(o shell GNU), infelizmente ainda não desencorajam seu uso nem os descontinuam.¹ mais sobre isso nesta minha resposta a um stackoverflow de perguntas e respostas relacionado
² a
test
/[
builtin só foi adicionado ao zsh na versão 2.0.3 em 1991. A[[ ... ]]
construção especial, do shell Korn sempre foi preferida lá, e tem sua própria sintaxe where&&
e||
são usados para e e ou operadores.O Bash analisa
[ ! -a WORD ]
sendo-a
o operador binário que significa “e”, cercado por dois testes de palavra única que são verdadeiros se não estiverem vazios. Assim[ ! -a "" ]
é falso e[ ! -a WORD ]
verdadeiro seWORD
não for vazio.Esta análise está em conformidade com a especificação POSIX (embora estritamente falando, não precisaria, pois unário
-a
não é especificado pelo POSIX). Aliás, mksh e zsh analisam este caso da mesma maneira, mas ksh93 analisa com unary!
seguido de unary-a
.Para evitar a ambiguidade, não use o
-a
operador obsoleto, use o-e
operador padrão, que não possui um operador binário com grafia idêntica. Além disso, para evitar ambiguidade ou erros em casos de canto mais longos, use&&
e||
como operadores binários (externo[ … ]
ou interno[[ … ]]
) em vez do potencialmente ambíguo-a
/-o
interno[ … ]
.