Quelle est la syntaxe d'une condition complexe dans le shell?

10

Si vous souhaitez exprimer le test suivant en shell (sh):

if ( a == 1 && ( b == 1 || b == 2 )) { ... }

Jusqu'à présent, le meilleur que j'ai pu écrire est le suivant:

if [[ $a -eq 1 ]]; then
  if [[ $b -eq 1 || $b -eq 2 ]]; then
     ...
  fi
fi

Je ne sais pas comment composer && et || avec une priorité correcte. La recherche sur Google ne m'a donné aucune réponse (les didacticiels ne donnent que des exemples de base, le cas échéant)

Quelle est la syntaxe pour combiner ces deux si en un seul?

Offirmo
la source
1
Une raison de ne pas utiliser ksh? Ensuite, votre code initial ne nécessiterait qu'une autre paire de parenthèses:if (( a == 1 && ( b == 1 || b == 2 ))); then :; fi
manatwork

Réponses:

14

Notez que ce [[ ]]n'est pas dans Bourne ou POSIX sh. Pour une véritable shsyntaxe, il existe plusieurs façons de procéder.

Utiliser une seule [ ]paire

if [ 1 -eq "$a" -a \( 1 -eq "$b" -o 2 -eq "$b" \) ]; then
    # ...
fi

ou Éviter le POSIX -aet les -ooptions 1

if [ 1 -eq "$a" ] && { [ 1 -eq "$b" ] || [ 2 -eq "$b" ]; }; then
    # ...
fi

1 L' une des raisons pour éviter -aet -oest une portabilité maximale - pas tout testou [mises en œuvre peuvent gérer plus de 4 arguments, ce qui est précisément ce que vous obtenez si vous enchaînez avec des expressions -aet -oet \( \).

jw013
la source
Mes scripts ont le #! / bin / sh shebang, et le shell par défaut est ksh . Pourquoi ne serait-il pas utilisé?
Offirmo
2
@Offirmo Si vous déclarez votre script comme /bin/sh, il est incorrect d'écrire le script en utilisant des fonctionnalités absentes sh. Vous devez savoir que ce kshn'est PAS sh, mais plutôt un surensemble de sh. Si vous apportez votre ksh-but-declare-as- shscript à un système où il shn'y a pas de lien symbolique ksh, il peut se casser. Vous pouvez éviter ce problème en vous assurant que votre script correspond à la déclaration.
jw013
Je pensais que définir / bin / sh comme shebang ferait invoquer mes scripts via / bin / sh . Voulez-vous dire que mon shell par défaut (ksh) ignore le shebang et l'interprète directement?
Offirmo
@Offirmo Vous avez raison: un shebang de /bin/shva invoquer /bin/sh. Le problème n'est /bin/shpas accepté [[. Vous ne pouvez pas utiliser [[ou utiliser un shell qui accepte [[, par exemple ksh, comme votre shebang.
jw013
2
Le problème n'est pas tant que -a/ qui -one sont pas pris en charge par certaines implémentations mais ce n'est pas fiable pour des arguments arbitraires. Like [ "$a" = "$b" -o "$b" = "$c" ]échouerait pour des valeurs de $alike !avec de nombreuses [implémentations.
Stéphane Chazelas
2

J'ai essayé une syntaxe et j'ai trouvé que

if [[ $a -eq 1 ]] && [[ $b -eq 1 || $b -eq 2 ]]; then
 ...
fi

travaille.

Offirmo
la source
1
cela fonctionne pour la version bash ci-dessus 4.
Nikhil Mulley
2

Une autre approche POSIX:

if [ "$((a == 1 && ( b == 1 || b == 2 )))" -ne 0 ]; then
  ...
fi
Stéphane Chazelas
la source
0

La bonne façon de le faire avec un simple shell:

if test 1 -eq "$a" && test 1 -eq "$b" -o 2 -eq "$b"; then 
    ...
fi

Explication:

testsert ici de parenthèse et -ode logique ou. Si vous une logique et à l'intérieur de la "parenthèse", vous utiliseriez -a.

Pour en savoir plus, cliquez ici

Omer Dagan
la source