Comment représenter des conditions multiples dans une instruction shell if?

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 celui si ....

Qu'est-ce qui ne va pas avec cette condition? Je suppose que quelque chose ne va pas avec le () .

232
demandé sur codeforester 2010-09-30 02:41:32

6 réponses

technique Classique d'échappement des caractères de remplacement):

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 parce que la préséance de -a et -o le rend correct même sans eux.

notez que les opérateurs -a et -o font partie de la spécification POSIX pour test , alias [ , principalement pour la rétrocompatibilité (puisqu'ils faisaient partie de test dans la 7ème édition D'UNIX, par exemple), mais ils sont explicitement marqués comme "obsolescents" par POSIX. Bash (voir expressions conditionnelles ) semble préférer les significations classique et POSIX pour -a et -o avec ses propres opérateurs alternatifs qui prennent des arguments.


avec un certain soin, vous pouvez utiliser le plus moderne [[ opérateur, mais être conscient que les versions dans Bash et Korn Shell (par exemple) n'ont pas besoin d'ê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 d'exécution, en utilisant Bash 3.2.57 sur 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 vous le faites avec [ parce que ce n'est pas une commande séparée de la même manière que [ est.


N'est-ce pas une question classique?

je l'aurais pensé. Toutefois, il existe une autre solution, à 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 le "portable shell" lignes directrices pour la autoconf de l'outil ou de paquets, cette notation en utilisant " || " et " && ' - est ce qu'ils recommandent. Je suppose que vous pourriez même aller jusqu'à:

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

où les actions sont aussi insignifiantes que en é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 douloureuse et l'une des versions précédentes est préférable - ou vous devez envelopper les actions dans une fonction qui est invoquée dans les différents blocs then .

297
répondu Jonathan Leffler 2015-05-03 15:43:01

Dans Bash:

if [[ ( $g == 1 && $c == 123 ) || ( $g == 2 && $c == 456 ) ]]
136
répondu Dennis Williamson 2010-09-29 23:46:35

par /bin/bash , on entend:

if [ "$option" = "Y" ] || [ "$option" = "y" ]; then
    echo "Entered $option"
fi
18
répondu sunitha 2016-09-23 12:12:24
$ 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
répondu ghostdog74 2010-09-30 03:06:04

soyez prudent si vous avez des espaces dans vos variables string et vous vérifiez l'existence. Assurez-vous de les citer correctement.

if [ ! "${somepath}" ] || [ ! "${otherstring}" ] || [ ! "${barstring}" ] ; then
5
répondu orkoden 2015-11-12 10:29:35
#!/bin/bash

current_usage=$( df -h | grep 'gfsvg-gfslv' | awk {'print '} )
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
répondu Debjyoti Banerjee 2018-05-04 23:48:22