web-dev-qa-db-fra.com

Comment représenter plusieurs conditions dans un shell si une déclaration?

Je veux représenter plusieurs conditions comme celle-ci:

if [ ( $g -eq 1 -a "$c" = "123" ) -o ( $g -eq 2 -a "$c" = "456" ) ]   
then  
    echo abc;  
else  
    echo efg;   
fi  

mais quand j'exécute le script, il montre

syntax error at line 15: `[' unexpected, 

où la ligne 15 est celle qui montre si .... 

Quel est le problème avec cette condition? Je suppose que quelque chose ne va pas avec le ().

252
user389955

Technique classique (métacaractères d'échappement):

if [ \( "$g" -eq 1 -a "$c" = "123" \) -o \( "$g" -eq 2 -a "$c" = "456" \) ]
then echo abc
else echo efg
fi

J'ai joint les références à $g entre guillemets; c'est une bonne pratique, en général. Strictement, les parenthèses ne sont pas nécessaires car la priorité de -a et -o le rend correct même sans elles.

Notez que les opérateurs -a et -o font partie de la spécification POSIX pour test , également appelé [, principalement pour des raisons de compatibilité ascendante (puisqu'ils faisaient partie de test dans 7th Edition UNIX, par exemple), mais ils sont explicitement marqués comme 'obsolescente' de POSIX. Bash (voir expressions conditionnelles ) semble préempter les significations classiques et POSIX pour -a et -o avec ses propres opérateurs alternatifs qui prennent des arguments.


Avec un peu de prudence, vous pouvez utiliser l'opérateur plus moderne [[, mais sachez que les versions de Bash et de Korn Shell (par exemple) ne doivent pas nécessairement être identiques.

for g in 1 2 3
do
    for c in 123 456 789
    do
        if [[ ( "$g" -eq 1 && "$c" = "123" ) || ( "$g" -eq 2 && "$c" = "456" ) ]]
        then echo "g = $g; c = $c; true"
        else echo "g = $g; c = $c; false"
        fi
    done
done

Exemple exécuté avec Bash 3.2.57 sous Mac OS X:

g = 1; c = 123; true
g = 1; c = 456; false
g = 1; c = 789; false
g = 2; c = 123; false
g = 2; c = 456; true
g = 2; c = 789; false
g = 3; c = 123; false
g = 3; c = 456; false
g = 3; c = 789; false

Vous n'avez pas besoin de citer les variables dans [[ comme avec [ car il ne s'agit pas d'une commande séparée de la même manière que [.


N'est-ce pas une question classique?

Je l'aurais pensé. Cependant, il existe une autre alternative, à savoir:

if [ "$g" -eq 1 -a "$c" = "123" ] || [ "$g" -eq 2 -a "$c" = "456" ]
then echo abc
else echo efg
fi

En effet, si vous lisez les instructions de '' shell portable '' pour l'outil autoconf ou les packages associés, cette notation - utilisant '||' et '&&' - correspond à leurs recommandations. Je suppose que vous pourriez même aller aussi loin que:

if [ "$g" -eq 1 ] && [ "$c" = "123" ]
then echo abc
Elif [ "$g" -eq 2 ] && [ "$c" = "456" ]
then echo abc
else echo efg
fi

Là où les actions sont aussi triviales que l'écho, ce n'est pas mauvais. Lorsque le bloc d'action à répéter est composé de plusieurs lignes, la répétition est trop pénible et l'une des versions antérieures est préférable: vous devez également intégrer les actions à une fonction appelée dans les différents blocs then.

317
Jonathan Leffler

Dans Bash:

if [[ ( $g == 1 && $c == 123 ) || ( $g == 2 && $c == 456 ) ]]
151
Dennis Williamson

En utilisant /bin/bash, ce qui suit fonctionnera:

if [ "$option" = "Y" ] || [ "$option" = "y" ]; then
    echo "Entered $option"
fi
22
sunitha

Faites attention si vous avez des espaces dans vos variables de chaîne et que vous vérifiez leur existence. Assurez-vous de les citer correctement.

if [ ! "${somepath}" ] || [ ! "${otherstring}" ] || [ ! "${barstring}" ] ; then
7
orkoden
$ g=3
$ c=133
$ ([ "$g$c" = "1123" ] || [ "$g$c" = "2456" ]) && echo "abc" || echo "efg"
efg
$ g=1
$ c=123
$ ([ "$g$c" = "1123" ] || [ "$g$c" = "2456" ]) && echo "abc" || echo "efg"
abc
7
ghostdog74
#!/bin/bash

current_usage=$( df -h | grep 'gfsvg-gfslv' | awk {'print $5'} )
echo $current_usage
critical_usage=6%
warning_usage=3%

if [[ ${current_usage%?} -lt ${warning_usage%?} ]]; then
echo OK current usage is $current_usage
Elif [[ ${current_usage%?} -ge ${warning_usage%?} ]] && [[ ${current_usage%?} -lt ${critical_usage%?} ]]; then
echo Warning $current_usage
else
echo Critical $current_usage
fi
0