Comment puis-je détecter qu'aucune option n'a été transmise avec getopts?

19

J'ai ce code -

#getoptDemo.sh
usage()
{
    echo "usage: <command> options:<w|l|h>"
}
while getopts wlh: option
do
    case $option in
            (w)
                    name='1';;
            (l)
                    name='2';;
            (h)
                    name='3';;
            (*)
                    usage
                    exit;;
    esac
done
print 'hi'$name

Lorsque je lance bash getoptDemos.sh(sans l'option), il s'imprime hiau lieu d'appeler la fonction usage. Il appelle usage lorsque des options autres que w, h et l sont données. Cela ne peut alors pas fonctionner si aucune option n'est spécifiée.

Je l' ai essayé d' utiliser ?, \?, :à la place de , *mais je ne peux pas obtenir ce que je voulais. Je veux dire tout docsle getoptdit qu'il faut utiliser ?.

Qu'est-ce que je fais mal?

Hussain Tamboli
la source
Sous quel shell l'utilisez-vous?
Julian
Je le dirige sous/bin/bash
Hussain Tamboli

Réponses:

15

Lorsque vous exécutez ce script sans aucune option, getopt retournera false, donc il n'entrera pas du tout dans la boucle. Il ne restera plus qu'à imprimer - est-ce ksh / zsh?

Si vous devez avoir une option, le mieux est de tester $ name après la boucle.

if [ -z "$name" ]
then
   usage
   exit
fi

Mais assurez-vous qu'il $nameétait vide avant d'appeler getopts(car il pourrait y avoir eu $namedans l'environnement le shell reçu au démarrage) avec

unset name

(avant la getoptsboucle)

julien
la source
non. son bash. Alors, comment puis-je atteindre ce que je veux - gérer la no argumentcondition à l'aide de bash.
Hussain Tamboli
Si vous voulez une option obligatoire, je ne pense pas que ce soit possible - c'est probablement pourquoi elles sont appelées options :) Vous pouvez cependant tester $ name, après la boucle pour vous assurer qu'elle a été définie. if [-z "$ name"]; puis utilisation; sortie ; fi
Julian
Merci. le code ci-dessus a vraiment aidé. Son dommage getoptsn'a pas une telle disposition. Le pire, c'est que vous ne pouvez pas voter.
Hussain Tamboli
et si j'utilisais un autre shell? zsh, sh. une coquille autre que bash prend-elle en charge cette condition?
Hussain Tamboli du
20

getoptstraite les options tour à tour. Voilà son travail. Si l'utilisateur ne passe aucune option, la première invocation de getoptsquitte la boucle while.

Si aucune des options ne prend d'argument, la valeur de OPTINDindique le nombre d'options transmises. En général, OPTINDc'est le nombre d'arguments qui sont des options ou des arguments pour les options, par opposition aux arguments sans option (opérandes).

while getopts …; do …; done
if [ $OPTIND -eq 1 ]; then echo "No options were passed"; fi
shift $((OPTIND-1))
echo "$# non-option arguments"

Dans tous les cas, vous n'essayez pas de déterminer s'il n'y avait pas d'options, mais si aucune des nameoptions de paramétrage n'a été transmise. Vérifiezname donc s'il n'est pas réglé (et prenez soin de le désactiver en premier) .

Gilles 'SO- arrête d'être méchant'
la source
1
Merci. +1 pour vous. lorsque je mets les 3 dernières lignes de votre code dans sample.sh et l'exécute, bash sample.sh -abc file.txtcela donne - 1 non-option arguments. comment savoir combien d'options ont été proposées. (ici 3)
Hussain Tamboli
1
Étrange, personne n'a commenté ce léger bug - si aucune option n'est donnée, OPTIND sera égal à 1 après cette boucle 'while getopts ...'. Ainsi, la vérification if doit vérifier l'égalité avec 1, et non avec zéro.
Daniel
4

Si votre script doit recevoir des arguments d'option dans tous les cas, placez ce bloc au début (avant les getops).

if [[ ! $@ =~ ^\-.+ ]]
then
  #display_help;
fi

Block vérifie que la chaîne de paramètres ne commence pas par un -symbole, ce qui indique que le premier paramètre n'est pas un argument d'option.

mcounad
la source
2

Je le vérifierais avec une variable. Si getopts ne passe jamais la boucle en cas d'absence d'argument, vous pouvez l'utiliser par exemple comme ceci:

#getoptDemo.sh
usage()
{
    echo "usage: <command> options:<w|l|h>"
}

no_args="true"
while getopts wlh: option
do
    case $option in
            (w)
                    name='1';;
            (l)
                    name='2';;
            (h)
                    name='3';;
            (*)
                    usage
                    exit;;
    esac
    no_args="false"
done

[[ "$no_args" == "true" ]] && { usage; exit 1; }

print 'hi'$name
Imre Kneifel
la source
0

Juste avant votre getoptsbloc, vérifiez si $1(le premier argument / option que vous avez passé sur la ligne de commande) est égal à une chaîne vide. Si c'est le cas, imprimez le message d'utilisation et quittez (ou exécutez une fonction "pas d'options" si vous êtes un anarchiste), sinon laissez getoptsanalyser les options comme d'habitude.

La raison pour laquelle cette fonctionnalité n'est pas incluse dans getopts, c'est que vous pouvez déjà l'accomplir dans bash avec un "if-else". Exemple:

if [[ $1 == "" ]]; then
    Your_Usage_Function;
    exit;
else
   #parse options with getopts code block here;
fi

Ça a du sens?

codrcodz
la source