Conditions Bash: comment «et» les expressions? (si [! -z $ VAR && -e $ VAR])

281

Je suppose que je ne sais pas trop comment faire "et" les tests. Je voulais m'assurer qu'il existait un argument qui fonctionnait bien [ -e $VAR ], mais il s'avère qu'il était également évalué comme vrai sur une chaîne vide; ce que je ne veux pas.

Comment puis-je les «et» ensemble? Ou existe-t-il un autre test unaire qui accomplit ce que je veux?

atxdba
la source

Réponses:

532
if [ ! -z "$var" ] && [ -e "$var" ]; then
      # something ...
fi
jaypal singh
la source
9
Cette solution fonctionne même dans des shells strictement POSIX et donc également dans bash; cependant, pour profiter pleinement des «bashismes», voir la réponse de @ paxdiablo.
mklement0
2
Très heureux de voir cela conseillé au lieu de l'obsolescence -a.
Charles Duffy
1
J'en ai trouvé une autre excellente et détaillée - stackoverflow.com/questions/3601515/…
valentt
70

Depuis la bashpage de manuel:

[[ expression ]] - retourner un état de 0 ou 1 selon l'évaluation de l'expression d'expression conditionnelle.

Et, pour les expressions, l'une des options est:

expression1 && expression2- vrai si les deux expression1et expression2sont vrais.

Vous pouvez donc andles regrouper comme suit ( -nc'est l'opposé de -zce que nous pouvons éliminer !):

if [[ -n "$var" && -e "$var" ]] ; then
    echo "'$var' is non-empty and the file exists"
fi

Cependant, je ne pense pas que ce soit nécessaire dans ce cas, -e xyzzyc'est vrai si le xyzzy fichier existe et peut assez facilement gérer des chaînes vides. Si c'est ce que vous voulez, vous n'avez pas réellement besoin de la -zvérification non vide:

pax> VAR=xyzzy
pax> if [[ -e $VAR ]] ; then echo yes ; fi
pax> VAR=/tmp
pax> if [[ -e $VAR ]] ; then echo yes ; fi
yes

En d'autres termes, utilisez simplement:

if [[ -e "$var" ]] ; then
    echo "'$var' exists"
fi
paxdiablo
la source
1
Nous pouvons le raccourcir avec[[ -e "$var" ]] && echo "'$var' exists"
Jaypal Singh
1
Oui, s'il s'agit d'un monoplace (comme mon exemple). Je ne ferais pas cela si le bloc conditionnel était beaucoup plus complexe.
paxdiablo
dans le cas où il n'y a qu'une seule commande - peut-être même longue -, il est logique d'utiliser ce formulaire car il est plus court
avp
9
if [ -n "$var" -a -e "$var" ]; then
    do something ...
fi

 

Slava Semushin
la source
10
Puisque POSIXne définit pas le comportement de [avec des ensembles de tests complexes, nous devons éviter d'utiliser -aou -oavec [. Je l'ai lu ici .
jaypal singh
2
@ jaypal-singh Vous avez raison, mais le sujet a une bashbalise et ne mentionne pas POSIX, donc je poste cette version qui fonctionne sous bashet quelques autres shells modernes.
Slava Semushin
2
Si vous supposez l'utilisation de bashou d'autres coquilles modernes, il y a encore moins de raisons de recommander -a.
chepner
Même avec bash, le comportement de ces tests n'est pas bien défini dans tous les cas d'angle. Considérez [ "$var1" -o "$var2" ]; si var1=(et var2=), alors ce que nous avons est un test pour savoir s'il -oest non vide, plutôt que si l'un var1ou l'autre var2n'est pas vide. Ce genre d'ambiguïté est la seule raison légitime de l' x$varidiome dans les commandes modernes (c'est-à-dire postérieures aux années 90) testavec des citations correctes, et cet idiome doit mourir dans un incendie.
Charles Duffy
4

Citez simplement votre variable:

[ -e "$VAR" ]

Cela évalue [ -e "" ]si$VAR est vide.

Votre version ne fonctionne pas car elle est évaluée [ -e ]. Dans ce cas, bash vérifie simplement si le seul argument (-e ) est une chaîne non vide.

Depuis la page de manuel:

tester et [évaluer les expressions conditionnelles à l'aide d'un ensemble de règles basées sur le nombre d'arguments. ...

1 argument

L'expression est vraie si et seulement si l'argument n'est pas nul.

(De plus, cette solution a l'avantage supplémentaire de travailler avec des noms de fichiers contenant des espaces)

user123444555621
la source
1

J'ai trouvé une réponse maintenant. Merci pour vos suggestions!

for e in ./*.cutoff.txt; do
if grep -q -E 'COX1|Cu-oxidase' $e
then
    echo xyz >$e.match.txt
else
    echo
fi

if grep -q -E 'AMO' $e
then
    echo abc >$e.match.txt
else
    echo
fi; done

Des commentaires à ce sujet? Il semble inefficace de grep deux fois, mais ça marche ...

rororo
la source