Quelle est la différence de -a et -e dans les expressions conditionnelles de bash?


12

De man bash:

CONDITIONAL EXPRESSIONS
[...]
       -a file
              True if file exists.
[...]
       -e file
              True if file exists.
  1. Quelle est donc la différence entre [ -a $FILE ]et [ -e $FILE ], le cas échéant?
  2. S'il n'y a pas de réelle différence, pourquoi existe-t-il deux drapeaux dans le même but?

Seuls les développeurs sauraient # 2 --- à moins qu'ils ne partagent leur raisonnement avec la communauté.
Belmin Fernandez

Réponses:


13

Dans bash, avec le contexte de la testcommande deux arguments , -a fileet -e filesont les mêmes. Mais ils ont une certaine différence, car -ac'est aussi un opérateur binaire.

-eunary est défini par POSIX, mais -aunary ne l'est pas. POSIX définit uniquement le -abinaire (voir test POSIX).

POSIX définit le testcomportement de trois arguments :

3 arguments:

  • Si $ 2 est un primaire binaire, effectuez le test binaire de $ 1 et $ 3.

  • Si $ 1 est '!', Annulez le test à deux arguments de $ 2 et $ 3.

  • Si $ 1 est '(' et 3 $ est ')', effectuez le test unaire de 2 $. Sur les systèmes qui ne prennent pas en charge l'option XSI, les résultats ne sont pas spécifiés si $ 1 est '(' et $ 3 est ')'.

  • Sinon, produisez des résultats non spécifiés.

Cela -aconduit également à un résultat étrange:

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

-aest considéré comme un opérateur binaire dans le contexte de trois arguments. Voir la question E1 de la FAQ Bash . POSIX mentionne également que cela -aprovient de KornShell mais a été changé plus tard en -ecar cela rend la confusion entre -abinaire et -aunaire.

Le -e primaire, possédant des fonctionnalités similaires à celles fournies par le shell C, a été ajouté car il fournit le seul moyen pour un script shell de savoir si un fichier existe sans essayer d'ouvrir le fichier. Étant donné que les implémentations sont autorisées à ajouter des types de fichiers supplémentaires, un script portable ne peut pas utiliser:

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

pour savoir si foo est un fichier existant. Sur les systèmes BSD historiques, l'existence d'un fichier peut être déterminée par:

test -f foo -o -d foo

mais il n'y avait pas de moyen facile de déterminer qu'un fichier existant était un fichier normal. Une première proposition a utilisé le KornShell -a primaire (avec la même signification), mais cela a été changé en -e parce qu'il y avait des inquiétudes concernant la forte probabilité que les humains confondent le -a primaire avec l'opérateur binaire -a.

-abinaire est également marqué comme obsolète, car il conduit à une expression ambiguë, qui a plus de 4 arguments. Avec ces expressions> 4 arguments, POSIX définit que le résultat n'est pas spécifié.


Cool à savoir! Maintenant c'est un peu plus clair :)!
polym

9

.1. Quelle est donc la différence entre [-a $ FILE] et [-e $ FILE], le cas échéant?

Il n'y a aucune différence.

En ligne 505-507avec test.cla version bash 4.2.45(1)-release:

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

Cela indique qu'il n'y a pas de réelle différence entre les deux drapeaux.

.2. S'il n'y a pas de réelle différence, pourquoi existe-t-il deux drapeaux dans le même but?

Voir la réponse de gnouc .


3
D'un autre côté, étant donné qu'il -as'agit également d' un opérateur booléen (et) dans bash, il semble sujet à des bogues d'ajouter cette signification supplémentaire qui est complètement redondante; Je suppose que c'est plus lié à la compatibilité avec une autre implémentation et / ou la compatibilité avec des versions antérieures qui n'en avaient pas -e.
celtschk

@celtschk - ce n'est pas bugprone, mais l'analyseur du shell peut l'être. POSIX spécifie les booléens -aet . Mais certains obus (comme ) ont réussi à distinguer un argument d'un opérateur et les résultats n'étaient pas fiables. Depuis lors, POSIX a exigé que tout shell compatible gère au moins 4 arguments entre crochets. -o[ test ]bash[ test ][ test ]
mikeserv

5

La meilleure réponse que j'ai trouvée est celle-ci, à partir d'une question StackOverflow:

-aest obsolète, il n'est donc plus répertorié dans la page de manuel pour /usr/bin/test, mais toujours dans celui de bash. Utilisez -e. Pour un simple «[», la fonction intégrée bash se comporte de la même manière que la fonction testintégrée bash, qui se comporte de la même manière /usr/bin/[que /usr/bin/test ( et l'un est un lien symbolique vers l'autre). Notez que l'effet de -adépend de sa position: s'il est au début, cela signifie file exists. Si c'est au milieu de deux expressions, cela signifie logique and.

[ ! -a /path ] && echo existsne fonctionne pas, comme le souligne le manuel bash qui -aest considéré comme un opérateur binaire, et donc ce qui précède n'est pas analysé comme un negate -a ..mais comme if '!' and '/path' is true(non vide). Ainsi, votre script sort toujours "-a"(qui teste réellement les fichiers), et "! -a"qui est en fait un binaire andici.

Car [[, -an'est plus utilisé comme binaire and(y &&est utilisé), son but unique est donc de rechercher un fichier là-bas (bien qu'il soit obsolète). La négation fait donc ce que vous attendez.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.