¿Cuál es la diferencia de -a y -e en las expresiones condicionales de bash?

12

De man bash:

CONDITIONAL EXPRESSIONS
[...]
       -a file
              True if file exists.
[...]
       -e file
              True if file exists.
  1. Entonces, ¿cuál es la diferencia entre [ -a $FILE ]y [ -e $FILE ], si hay alguno?
  2. Si no hay una diferencia real, ¿por qué existen dos banderas con el mismo propósito?
polimero
fuente
Solo los desarrolladores sabrían # 2 --- a menos que compartieran su razonamiento con la comunidad.
Belmin Fernández

Respuestas:

13

En bash, con el contexto de dos argumentos testcomando, -a filey -e fileson los mismos. Pero tienen alguna diferencia, porque -atambién es un operador binario.

-ePOSARIO define unario, pero -ano lo es unario. POSIX solo define -abinarios (Ver prueba POSIX).

POSIX define tres argumentos de testcomportamiento:

3 argumentos:

  • Si $ 2 es un primario binario, realice la prueba binaria de $ 1 y $ 3.

  • Si $ 1 es '!', Niegue la prueba de dos argumentos de $ 2 y $ 3.

  • Si $ 1 es '(' y $ 3 es ')', realice la prueba unaria de $ 2. En los sistemas que no admiten la opción XSI, los resultados no se especifican si $ 1 es '(' y $ 3 es ')'.

  • De lo contrario, producir resultados no especificados.

Entonces -atambién conduce a un resultado extraño:

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

-ase considera como operador binario en el contexto de tres argumentos. Consulte la pregunta frecuente Bash E1 . POSIX también menciona que -ase obtiene de KornShell, pero se cambió más tarde -eporque es confuso entre -abinario y -aunario.

El -e primario, que posee una funcionalidad similar a la proporcionada por el shell C, se agregó porque proporciona la única forma para que un script de shell descubra si existe un archivo sin intentar abrir el archivo. Dado que las implementaciones pueden agregar tipos de archivos adicionales, un script portátil no puede usar:

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

para averiguar si foo es un archivo existente. En sistemas BSD históricos, la existencia de un archivo podría determinarse por:

prueba -f foo -o -d foo

pero no había una manera fácil de determinar que un archivo existente era un archivo normal. Una propuesta inicial usaba el KornShell -a primario (con el mismo significado), pero esto se cambió a -e porque había dudas sobre la alta probabilidad de que los humanos confundan el operador -a primario con el operador binario -a.

-abinario también se marca como obsoleto, porque conduce a una expresión ambigua, que tiene más de 4 argumentos. Con esta expresión de> 4 argumentos, POSIX define que el resultado no está especificado.

Cuonglm
fuente
Genial saberlo! Ahora está un poco más claro :)!
polym
9

.1. Entonces, ¿cuál es la diferencia entre [-a $ FILE] y [-e $ FILE], si corresponde?

No hay diferencia en absoluto.

En línea 505-507en test.cla versión bash 4.2.45(1)-release:

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

Eso indica que no hay una diferencia real entre ambas banderas.

.2. Si no hay una diferencia real, ¿por qué existen dos banderas con el mismo propósito?

Ver la respuesta de gnouc .

polimero
fuente
3
Por otro lado, dado que también-a es un operador booleano (y) en bash, parece propenso a errores agregar este significado adicional que es completamente redundante; Supongo que está más relacionado con la compatibilidad con alguna otra implementación y / o compatibilidad con versiones anteriores que no tenían . -e
celtschk
@celtschk: no tiene errores, pero el analizador de shell puede serlo. POSIX especifica los -ay -obooleanos para [ test ]. Pero algunos shells (como bash) apestaban al distinguir un argumento de un operador y los [ test ]resultados no eran confiables. Desde entonces, POSIX ha requerido que cualquier shell compatible maneje al menos 4 argumentos dentro de los [ test ]corchetes.
mikeserv
5

La mejor respuesta que he encontrado es esta, de una pregunta de StackOverflow:

-aestá en desuso, por lo que ya no aparece en la página de manual /usr/bin/test, pero aún está en el de bash. Uso -e. Para un solo '[', el bash builtin se comporta igual que el testbash builtin, que se comporta igual que /usr/bin/[y /usr/bin/test (el uno es un enlace simbólico al otro). Tenga en cuenta que el efecto de -adepende de su posición: si está al principio, significa file exists. Si está en el medio de dos expresiones, significa lógico and.

[ ! -a /path ] && echo existsno funciona, ya que el manual de bash señala que -ase considera un operador binario allí, por lo que lo anterior no se analiza como un negate -a ..sino como if '!' and '/path' is true(no vacío). Por lo tanto, su script siempre genera "-a"(que realmente prueba los archivos), y "! -a"que en realidad es un binario andaquí.

Para [[, -ano se utiliza como un binario andmás ( &&se utiliza allí), por lo que su única finalidad es comprobar que un archivo existe (aunque se use). Entonces, la negación realmente hace lo que esperas.

jimm-cl
fuente