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

11

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 houver diferença real, por que existem duas bandeiras para o mesmo propósito?
por polym 31.07.2014 / 20:19

3 respostas

12

Em bash , com contexto de dois argumentos test comando, -a file e -e file são iguais. Mas eles têm alguma diferença, porque -a também é um operador binário.

-e unary é definido por POSIX, mas -a unary não é. POSIX só define -a binário (veja teste POSIX).

POSIX define três argumentos test behavior:

3 arguments:

  • If $2 is a binary primary, perform the binary test of $1 and $3.

  • If $1 is '!', negate the two-argument test of $2 and $3.

  • If $1 is '(' and $3 is ')', perform the unary test of $2. On systems that do not support the XSI option, the results are unspecified if $1 is '(' and $3 is ')'.

  • Otherwise, produce unspecified results.

Portanto, -a também leva a resultados estranhos:

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

-a é considerado como operador binário no contexto de três argumentos. Consulte a pergunta sobre perguntas frequentes E1 . O POSIX também menciona que -a é obtido do KornShell, mas foi alterado posteriormente para -e porque confunde entre -a binary e -a unary.

The -e primary, possessing similar functionality to that provided by the C shell, was added because it provides the only way for a shell script to find out if a file exists without trying to open the file. Since implementations are allowed to add additional file types, a portable script cannot use:

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

to find out if foo is an existing file. On historical BSD systems, the existence of a file could be determined by:

test -f foo -o -d foo

but there was no easy way to determine that an existing file was a regular file. An early proposal used the KornShell -a primary (with the same meaning), but this was changed to -e because there were concerns about the high probability of humans confusing the -a primary with the -a binary operator.

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

    
por 31.07.2014 / 20:57
8

.1. So what is the difference between [ -a $FILE ] and [ -e $FILE ], if any?

Não há diferença alguma.

Na linha 505-507 em test.c da versão 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 flags.

.2. If there is no real difference, why do two flags for the same purpose exist?

Veja a resposta do gnouc .

    
por 31.07.2014 / 20:26
4

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

-a is deprecated, thus isn't listed in the manpage for /usr/bin/test anymore, but still in the one for bash. Use -e . For single '[', the bash builtin behaves the same as the test bash builtin, which behaves the same as /usr/bin/[ and /usr/bin/test (the one is a symlink to the other). Note the effect of -a depends on its position: If it's at the start, it means file exists. If it's in the middle of two expressions, it means logical and.

[ ! -a /path ] && echo exists doesn't work, as the bash manual points out that -a is considered a binary operator there, and so the above isn't parsed as a negate -a .. but as a if '!' and '/path' is true (non-empty). Thus, your script always outputs "-a" (which actually tests for files), and "! -a" which actually is a binary and here.

For [[, -a isn't used as a binary and anymore (&& is used there), so its unique purpose is to check for a file there (although being deprecated). So, negation actually does what you expect.

    
por 31.07.2014 / 21:03

Tags