Vérifier si l'un des paramètres d'un script bash correspond à une chaîne

67

J'essaie d'écrire un script dans lequel je veux vérifier si l'un des paramètres transmis à un script bash correspond à une chaîne. La façon dont je l'ai configuré en ce moment est

if [ "$3" != "-disCopperBld" -a "$4" != "-disCopperBld" -a "$5" != "-disCopperBld" -a "$6" != "-disCopperBld"]

mais il pourrait y avoir un grand nombre de paramètres, alors je me demandais s'il y avait une meilleure façon de faire cela?

Merci

EDIT: J'ai essayé cette partie de code et appelé le script avec l'option -disableVenusBld, mais il affiche toujours "Démarrage de la construction". Est-ce que je fais quelque chose de mal? Merci d'avance!

while [ $# -ne 0 ]
do
    arg="$1"
    case "$arg" in
        -disableVenusBld)
            disableVenusBld=true
            ;;
        -disableCopperBld)
            disableCopperBld=true
            ;;
        -disableTest)
            disableTest=true
            ;;
        -disableUpdate)
            disableUpdate=true
            ;;
        *)
            nothing="true"
            ;;
    esac
    shift
done

if [ "$disableVenusBld" != true ]; then
    echo "Starting build"
fi
iman453
la source
Merci pour les réponses les gars, j'apprécie que vous preniez le temps de m'aider. J'ai essayé un morceau de code, mais je n'arrive pas à comprendre ce qui ne va pas. Des idées? (J'ai collé le code dans une édition de mon message original)
iman453
Hmm: ça marche pour moi. J'ai ajouté #! /bin/sh -en haut de ce que vous avez inclus ici, rendu le script exécutable, puis ./t.shimprimé "Démarrage de la construction", mais ./t.sh -disableVenusBldn'imprime rien.
Norman Gray

Réponses:

59

Il semble que vous soyez en train de gérer des options dans un script shell. Voici l'idiome pour cela:

#! /bin/sh -

# idiomatic parameter and option handling in sh
while test $# -gt 0
do
    case "$1" in
        --opt1) echo "option 1"
            ;;
        --opt2) echo "option 2"
            ;;
        --*) echo "bad option $1"
            ;;
        *) echo "argument $1"
            ;;
    esac
    shift
done

exit 0

(Il existe quelques conventions pour indenter le ;;, et certains shells vous permettent de donner les options comme (--opt1), pour aider à la correspondance d'accolade, mais c'est l'idée de base)

Norman Gray
la source
3
Une shiftinstruction est utilisée lorsque le nombre d'arguments d'une commande n'est pas connu à l'avance, par exemple lorsque les utilisateurs peuvent donner autant d'arguments qu'ils le souhaitent. Dans ce cas, les arguments sont traités dans une whileboucle avec une condition de test de $#. Cette condition est vraie tant que le nombre d'arguments est supérieur à zéro. La $1variable et l' shiftinstruction traitent chaque argument. Le nombre d'arguments est réduit à chaque shiftexécution et atteint finalement zéro, après quoi la whileboucle se termine. source
Serge Stroobandt
Voici un exemple similaire avec un echo $1 | sedtraitement de valeur d'argument supplémentaire .
Serge Stroobandt le
26

Cela a fonctionné pour moi. Il fait exactement ce que vous avez demandé et rien de plus (pas d’option de traitement). Que ce soit bon ou mauvais est un exercice pour l'affiche :)

if [[ "$*" == *YOURSTRING* ]]
then
    echo "YES"
else
    echo "NO"
fi

Cela tire parti de la manipulation spéciale des supports $* et du super-test [[… bash ]].

Rich Homolka
la source
2
IMHO cela devait être la réponse la plus correcte, car la question ne demandait que de vérifier la présence d'un paramètre. Cependant, j'ai changé $*en $@, car la chaîne à tester peut comporter des espaces et un lien vers la documentation de bash à ce sujet.
h7r
9
Vouliez-vous utiliser l'opérateur = ~? Sinon, je ne vois pas pourquoi cela devrait fonctionner, et en effet cela ne fonctionne pas lorsque j'essaie le script exact.
Seppo Enarvi
3
Ne fonctionne pas bash -c 'echo args=$*; [[ "$@" == "bar" ]] && echo YES || echo NO' -- foo bar
Tobia
2
Ceci compare la liste d'arguments complète avec your string. Je pense que vous devez faire ce qui est suggéré par cette réponse . c'est-à-dire: bash -c 'echo args=$*; for i in "$@" ; do [[ $i == "bar" ]] && echo "Is set!" && break ; done' -- bar foofonctionnerait.
Starfry
2
Cette réponse est fausse depuis quatre ans parce que l'édition de h7r l'a brisée. La réponse originale (que j'ai maintenant restaurée) fonctionne, à condition que "votre chaîne" ne contienne aucun caractère global et comporte quelques faux positifs. Par exemple, si la commande est create a new certificateet que «votre chaîne» l'est cat, cela indiquera une correspondance car certificate contient cat .
Scott
8

Que diriez-vous de chercher (avec des caractères génériques) tout l'espace des paramètres:

if [[ $@ == *'-disableVenusBld'* ]]
then

Edit: Ok, ok, donc ce n'était pas une réponse populaire. Que diriez-vous de celui-ci, c'est parfait !:

if [[ "${@#-disableVenusBld}" = "$@" ]]
then
    echo "Did not find disableVenusBld"
else
    echo "Found disableVenusBld"
fi

Edit2: Ok, ok, peut-être que ce n'est pas parfait ... Pensez que cela ne fonctionne que si -param est au début de la liste et correspondra également à -paramXZY ou -paramABC. Je pense toujours que le problème original peut être résolu très bien avec la manipulation de bash, mais je ne l’ai pas encore fait craquer ici ... - Peux-tu ??

Riches
la source
Votre deuxième suggestion - comparer la substitution de filtrage à la substitution complète - fonctionne relativement bien et présente l’avantage de ne pas perturber la liste des arguments.
Donal Fellows
Pourriez-vous expliquer ce que fait la deuxième suggestion (en particulier ${@#)?
velop
1
@ enveloppe bien sûr! Vous savez donc que $@cette variable spéciale contient tous les arguments de la ligne de commande? Eh bien, je viens d'utiliser la manipulation de chaîne Bash sur cette variable pour supprimer la sous-chaîne "-disableVenusBld", puis je la compare à l'original $@. Donc, si $@égaux, -foo -barils le ${@#-disableVenusBld}seraient toujours -foo -bar, alors je peux voir que le drapeau que je cherche n'est pas présent. Cependant, si $@égaux, -foo -disableVenusBld -baralors ${@#-disableVenusBld}ce -foo -barqui n'est pas égal $@, me dit donc que le drapeau que je cherche est présent! Cool hein!
Rich
@velop En savoir plus sur la manipulation des chaînes Bash ici: tldp.org/LDP/abs/html/string-manipulation.html
Rich
@ Rich assez soigné ^^, merci pour l'explication.
velop
4
disCopperBld=
for x; do
  if [ "$x" = "-disCopperBld" ]; then disCopperBld=1; break; fi
done
if [ -n "$disCopperBld" ]; then
  ...
fi

Si vous ne devez tester que les paramètres à partir de $3, effectuez la recherche dans une fonction:

## Usage: search_trailing_parameters NEEDLE NUM "$@"
## Search NEEDLE amongst the parameters, skipping $1 through ${$NUM}.
search_trailing_parameters () {
  needle=$1
  shift $(($2 + 2))
  for x; do
    if [ "$x" = "$needle" ]; then return 0; fi
  done
  return 1
}
if search_trailing_parameters -disCopperBld 2 "$@"; then
  ...
fi

Mais je me demande pourquoi vous essayez de faire cela au départ, ce n'est pas un besoin commun. Habituellement, vous traitez les options dans l'ordre, comme dans la réponse de Dennis à votre question précédente .

Gilles, arrête de faire le mal
la source