web-dev-qa-db-fra.com

bash si l'option -a vs -e

Les deux -a et -e options dans documentation Bash est dit:

-a file
    True if file exists.
-e file
    True if file exists. 

En essayant de comprendre la différence, j'ai exécuté le script suivant:

resin_dir=/Test/Resin_wheleph/Results

if [ -e ${resin_dir} ] ; then
    echo "-e ";
fi

if [ ! -e ${resin_dir} ] ; then
    echo "! -e";
fi

if [ -a ${resin_dir} ] ; then
    echo "-a";
fi

if [ ! -a ${resin_dir} ] ; then
    echo "! -a";
fi

/Test/Resin_wheleph/Results existe et est un répertoire. Et voici ce que j'obtiens:

-e
-a
! -a

ce qui semble un peu étrange (remarquez -a et ! -a). Mais quand j'utilise des crochets doubles (par exemple, _ if [[ -e ${resin_dir} ]]) dans le script similaire, il donne une sortie raisonnable:

-e
-a

Donc:

  1. Quelle est la différence entre -a et -e options?
  2. Pourquoi -a produit un résultat étrange lorsqu'il est utilisé à l'intérieur de crochets simples?
54
wheleph

J'ai fait des recherches, et c'est assez poilu:

-a est obsolète, il n'est donc pas répertorié dans la page de manuel de /usr/bin/test plus, mais toujours dans celui de bash. Utilisation -e. Pour le '[' simple, le module intégré bash se comporte de la même façon que le module intégré test bash, qui se comporte de la même manière que /usr/bin/[ et /usr/bin/test (l'un est un lien symbolique vers l'autre). Notez l'effet de -a dé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 exists ne fonctionne pas, car le manuel bash souligne que -a est considéré comme un opérateur binaire, et donc ce qui précède n'est pas analysé en tant que negate -a .. mais en tant que if '!' and '/path' is true (non vide). Ainsi, votre script génère toujours "-a" (qui teste les fichiers) et "! -a" qui est en fait un binaire and ici.

Pour [[, -a n'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.

66

L'option '-a' De l'opérateur de test a une signification en tant qu'opérateur unaire et une autre en tant qu'opérateur binaire. En tant qu'opérateur binaire, c'est le connectif 'et' (et '-o' Est le 'ou' connectif). En tant qu'opérateur unaire, il teste apparemment l'existence d'un fichier.

Le système autoconf vous conseille d'éviter d'utiliser '-a' Car cela crée de la confusion; maintenant je vois pourquoi. En effet, dans la programmation Shell portable, il est préférable de combiner les conditions avec '&&' Ou '||'.

Je pense que @litb est sur la bonne voie. Lorsque vous avez '! -a ${resin_dir}', Bash peut l'interpréter comme "est la chaîne '!' non vide et est la chaîne dans '$ {resin_dir}' non vide, à laquelle la réponse est oui. Le Korn Shell a une vue différente à ce sujet, et le Bourne Shell encore une autre vue - alors restez à l'écart de '-a '.

Sous Solaris 10:

$ bash -c 'x=""; if [ ! -a "$x" ] ; then echo OK ; else echo Bad; fi'
Bad
$ ksh -c 'x=""; if [ ! -a "$x" ] ; then echo OK ; else echo Bad; fi'
OK
$ sh -c 'x=""; if [ ! -a "$x" ] ; then echo OK ; else echo Bad; fi'
sh: test: argument expected
$
3
Jonathan Leffler

Le double crochet [[exp]] est une commande bash intégrée. En bash, -a et -e sont les mêmes, probablement pour une certaine compatibilité descendante.

Le crochet simple [exp] est un alias pour la commande externe "test". Dans "test", -a est un ET logique. Bien que [rien AND $ STRING] semble être faux, test a quelques bizarreries syntaxiques, c'est pourquoi je recommande d'utiliser le bash intégré [[exp]], qui a tendance à être plus sain d'esprit.

Remarque: bash appelle vraiment/bin/[lorsque vous utilisez "[".

$ [ $UNASIGNED_VAR == "bar" ]
bash: [: ==: unary operator expected

l'erreur montre bash appelé [. Une strace affiche également "execve ("/usr/bin/[", ..."

0
JimB