J’essayais de combiner la logique AND & OR dans un script bash si condition. D’une certaine manière, je n’obtiens pas la sortie souhaitée et il est difficile de résoudre le problème. J’essaie de valider les parameters d’entrée passés à un script shell pour aucun paramètre et le premier paramètre passé est valide ou non.
if [ "$#" -ne 1 ] && ([ "$1" == "ABC" ] || [ "$1" == "DEF" ] || [ "$1" == "GHI" ] || [ "$1" == "JKL" ]) then echo "Usage: ./myscript.sh [ABC | DEF | GHI | JKL]" exit 1 fi
Quelqu’un peut-il indiquer ce qui ne va pas ici?
Le problème immédiat avec votre déclaration est un problème de logique : vous vouliez probablement écrire:
if [ "$#" -ne 1 ] || ! ([ "$1" = "ABC" ] || [ "$1" = "DEF" ] || [ "$1" = "GHI" ] || [ "$1" = "JKL" ]) then echo "Usage: ./myscript.sh [ABC | DEF | GHI | JKL]" >&2 exit 1 fi
C’est-à-dire: abort, si l’un des arguments est supérieur à 1 ou si l’argument donné n’est PAS égal à l’une des valeurs acceptables.
Notez le !
pour annuler l’expression entre parenthèses et l’utilisation de la forme conforme à POSIX de l’opérateur d’égalité de chaîne, =
(plutôt que ==
).
Cependant, étant donné que vous utilisez Bash, vous pouvez vous débrouiller avec un opérateur [[ ... ]]
conditionnel et un opérateur de correspondance des expressions régulières de Bash, =~
:
if [[ $# -ne 1 || ! $1 =~ ^(ABC|DEF|GHI|JKL)$ ]] then echo "Usage: ./myscript.sh [ABC | DEF | GHI | JKL]" >&2 exit 1 fi
Si la conformité à POSIX n’est pas requirejse, [[ ... ]]
est préférable à [ ... ]
pour diverses raisons . En l’espèce, $#
et $1
n’ont pas besoin d’être cotés, et ||
pourrait être utilisé à l’ intérieur du conditionnel.
Notez que =~
tel qu’utilisé ci-dessus fonctionne dans Bash 3.2+, alors que la syntaxe extglob
implicite utilisée dans la réponse utile de anubhava nécessite Bash 4.1+;
dans les versions précédentes, vous pouvez cependant activer explicitement (et restaurer sa valeur d’origine après) l’option de shell shopt -s extglob
: shopt -s extglob
.
BASH permet en fait l’utilisation de glob étendu à l’intérieur de [[ ... ]]
et &&
aussi &&
intérieur.
Donc, vous pouvez faire:
if [[ $# -ne 1 && $1 == @(ABC|DEF|GHI|JKL) ]]; then echo "Usage: ./myscript.sh [ABC | DEF | GHI | JKL]" exit 1 fi
Quelques choses:
[...]
dans bash équivaut à la même commande de test
(vérifiez la page de manuel), donc ceux && et || ne sont pas des opérateurs logiques, mais plutôt les équivalents shell -a
et -o
(en faisant votre instruction if [ "$#" -ne 1 -a \( "$1" == "ABC" -o "$1" == "DEF" -o "$1" == "GHI" -o "$1" == "JKL" \) ]
bien que selon votre logique, vous ayez envie de quelque chose comme if [ "$#" -ne 1 -o \( "$1" != "ABC" -a "$1" != "DEF" -a "$1" != "GHI" -a "$1" != "JKL" \) ]
. Vous pouvez probablement obtenir de meilleurs résultats avec une déclaration de case
comme suit: usage() { echo "Usage: ./myscript.sh [ABC | DEF | GHI | JKL]" } if [ "$#" -ne 1 ] then usage exit 1 fi case "$1" in ABC) echo "Found ABC" ;; DEF) echo "Found DEF" ;; GHI) echo "Found GHI" ;; JKL) echo "Found JKL" ;; *) usage exit 1 ;; esac
Si vous souhaitez transmettre un ensemble d’arguments statiques possibles, vous pouvez consulter la commande shell spéciale getopts
.