Qual é a diferença de -a e -e nas expressões condicionais do bash?

12

De man bash:

CONDITIONAL EXPRESSIONS
[...]
       -a file
              True if file exists.
[...]
       -e file
              True if file exists.
  1. Então, qual é a diferença entre [ -a $FILE ]e [ -e $FILE ], se houver?
  2. Se não há diferença real, por que existem duas bandeiras para o mesmo objetivo?
polym
fonte
Somente os desenvolvedores saberiam o número 2 - a menos que compartilhem seu raciocínio com a comunidade.
Belmin Fernandez 31/07

Respostas:

13

Em bash, com contexto de dois argumentos de testcomando -a filee -e filesão os mesmos. Mas eles têm alguma diferença, porque -atambém é um operador binário.

-eunário é definido pelo POSIX, mas -aunário não é. O POSIX define apenas -abinário (consulte o teste POSIX).

O POSIX define o testcomportamento de três argumentos :

3 argumentos:

  • Se $ 2 for um primário binário, execute o teste binário de $ 1 e $ 3.

  • Se $ 1 for '!', Negue o teste de dois argumentos de $ 2 e $ 3.

  • Se $ 1 é '(' e $ 3 é ')', execute o teste unário de $ 2. Em sistemas que não suportam a opção XSI, os resultados não são especificados se $ 1 for '(' e $ 3 é ')'.

  • Caso contrário, produza resultados não especificados.

Então -atambém leva a um resultado estranho:

$ [ ! -a . ] && echo true
true

-aé considerado como operador binário no contexto de três argumentos. Consulte a pergunta E1 da FAQ do Bash . O POSIX também menciona que -aé obtido do KornShell, mas foi alterado posteriormente para -eporque torna confuso entre -abinário e -aunário.

O primário -e, com funcionalidade semelhante à fornecida pelo shell C, foi adicionado porque fornece a única maneira de um script de shell descobrir se existe um arquivo sem tentar abri-lo. Como as implementações têm permissão para adicionar tipos de arquivos adicionais, um script portátil não pode usar:

teste -b foo -o -c foo -o -d foo -o -f foo -o -p foo

para descobrir se foo é um arquivo existente. Em sistemas BSD históricos, a existência de um arquivo pode ser determinada por:

teste -f foo -o -d foo

mas não havia uma maneira fácil de determinar se um arquivo existente era regular. Uma proposta inicial usava o KornShell -a primário (com o mesmo significado), mas isso foi alterado para -e porque havia preocupações sobre a alta probabilidade de humanos confundirem o primário -a com o operador binário -a.

-abinário também é marcado como obsoleto, porque leva a alguma expressão ambígua, com mais de 4 argumentos. Com essa expressão> 4 argumentos, o POSIX define que o resultado não é especificado.

cuonglm
fonte
Legal saber! Agora está um pouco mais claro :)!
polímer
9

.1. Então, qual é a diferença entre [-a $ FILE] e [-e $ FILE], se houver?

Não há nenhuma diferença.

Em linha 505-507no test.cda versão do bash 4.2.45(1)-release:

case 'a':           /* file exists in the file system? */
case 'e':
  return (sh_stat (arg, &stat_buf) == 0);

Isso indica que não há diferença real entre os dois sinalizadores.

.2. Se não há diferença real, por que existem duas bandeiras para o mesmo objetivo?

Veja a resposta do gnouc .

polym
fonte
3
Por outro lado, dado que também-a é um operador booleano (e) no bash, parece propenso a erros adicionar esse significado adicional que é completamente redundante; Eu acho que está mais relacionado à compatibilidade com alguma outra implementação e / ou compatibilidade com versões anteriores que não tinham . -e
Celtschk
@celtschk - não é propenso a erros, mas pode ser o analisador do shell. POSIX especifica os -ae -obooleanos para [ test ]. Porém, algumas conchas (como bash) foram úteis para distinguir um argumento de um operador e os [ test ]resultados não eram confiáveis. Desde então, o POSIX exigiu que qualquer shell compatível lide com pelo menos 4 argumentos entre [ test ]colchetes.
precisa saber é o seguinte
5

A melhor resposta que encontrei é esta, de uma pergunta do StackOverflow:

-afoi descontinuado e, portanto, não está mais listado na página de manual /usr/bin/test, mas ainda no do bash. Use -e. Para single '[', o bash builtin se comporta da mesma forma que o testbash builtin, que se comporta da mesma forma que /usr/bin/[e /usr/bin/test (esse é um link simbólico para o outro). Observe que o efeito de -adepende da sua posição: se é no início, significa file exists. Se estiver no meio de duas expressões, significa lógico and.

[ ! -a /path ] && echo existsnão funciona, como o manual do bash indica que -aé considerado um operador binário lá e, portanto, o acima não é analisado como um negate -a ..mas como um if '!' and '/path' is true(não vazio). Assim, seu script sempre gera "-a"(o que realmente testa arquivos) e o "! -a"que é realmente um binário andaqui.

Pois [[, -anão é mais usado como binário and( &&é usado lá), portanto, seu objetivo exclusivo é procurar um arquivo lá (apesar de estar obsoleto). Então, a negação realmente faz o que você espera.

jimm-cl
fonte