Comment puis-je ajouter une méthode d'aide à un script shell?
128
Comment vérifier si un -hattribut a été passé dans un script shell? Je souhaite afficher un message d'aide lorsqu'un utilisateur appelle myscript.sh -h.
usage="$(basename "$0") [-h] [-s n] -- program to calculate the answer to life, the universe and everything
where:
-h show this help text
-s set the seed value (default: 42)"
seed=42while getopts ':hs:' option;docase"$option"in
h) echo "$usage"
exit
;;
s) seed=$OPTARG
;;:) printf "missing argument for -%s\n""$OPTARG">&2
echo "$usage">&2
exit 1;;
\?) printf "illegal option: -%s\n""$OPTARG">&2
echo "$usage">&2
exit 1;;esacdone
shift $((OPTIND -1))
J'essaye ceci dans une fonction, mais quand j'essaye d'exécuter la fonction j'obtiens cette erreur "basename: option invalide - 'b'". On dirait qu'il essaie de passer "-bash" basenameavec le tiret de tête.
Morgan Estes
5
imside une fonction utiliser "$FUNCNAME"pas "$0". Aussi, ajouterlocal OPTIND OPTARG
glenn jackman
Merci. FUNCNAMEtravaux. J'ai toutes mes fonctions dans un seul fichier, c'est donc parfait pour les étendre en quelque chose d'utile pour les autres.
Morgan Estes
5
@sigur, assurez-vous de citer "$usage"chaque endroit où vous l'utilisez.
glenn jackman
1
Quel est le shift $((OPTIND - 1))pour?
hpaknia
45
Le premier argument d'un script shell est disponible comme variable $1, donc l'implémentation la plus simple serait
Merci @MarkBooth, faute de frappe corrigée (plus amélioration par mise entre guillemets)
seb
Vous devriez prendre l'habitude d'envelopper le if in [...] pour les conditionnels pour éviter une mauvaise analyse d'une variable, source: github.com/bahamas10/bash-style-guide#bashisms
JREAM
2
Oui, bien que l'OP n'ait pas spécifié bash et qu'il s'agisse de la [version compatible POSIX.
seb
Remarque - Pour une utilisation à l'intérieur function: vous devez remplacer exit 0par returnsi vous ne voulez pas terminer votre shell après avoir exécuté votre fonction. (Je l'ai fait avant 😂)
Illuminator
29
voici une partie que je l'utilise pour démarrer un serveur VNC
#!/bin/bash
start(){
echo "Starting vnc server with $resolution on Display $display"#your execute command here mine is below#vncserver :$display -geometry $resolution}
stop(){
echo "Killing vncserver on display $display"#vncserver -kill :$display}########################## The command line help ##########################
display_help(){
echo "Usage: $0 [option...] {start|stop|restart}">&2
echo
echo " -r, --resolution run with the given resolution WxH"
echo " -d, --display Set on which display to host on "
echo
# echo some stuff here for the -a or --add-options
exit 1}################################# Check if parameters options ## are given on the commandline #################################while:docase"$1"in-r |--resolution)if[ $# -ne 0 ]; then
resolution="$2"# You may want to check validity of $2fi
shift 2;;-h |--help)
display_help # Call your function
exit 0;;-d |--display)
display="$2"
shift 2;;-a |--add-options)# do something here call function# and write it in your help function display_help()
shift 2;;--)# End of all options
shift
break;;-*)
echo "Error: Unknown option: $1">&2## or call function display_help
exit 1;;*)# No more optionsbreak;;esacdone###################### # Check if parameter ## is set too execute #######################case"$1"in
start)
start # calling function start();;
stop)
stop # calling function stop();;
restart)
stop # calling function stop()
start # calling function start();;*)# echo "Usage: $0 {start|stop|restart}" >&2
display_help
exit 1;;esac
C'est un peu bizarre que j'ai placé le redémarrage start stop dans un cas séparé mais cela devrait fonctionner
si vous donnez une option vide à -d; n'est-ce pas une boucle infinie?
zerobane le
Pourquoi quittez-vous 1 dans la fonction d'assistance?
jeantimex le
17
Pour une solution rapide à option unique, utilisez if
Si vous n'avez qu'une seule option à vérifier et que ce sera toujours la première option ( $1), alors la solution la plus simple est une ifavec un test ( [). Par exemple:
Notez que pour posix, la compatibilité =fonctionnera aussi bien que ==.
Pourquoi citer $1?
La raison pour laquelle il $1faut mettre entre guillemets est que s'il n'y en a pas, $1le shell essaiera de s'exécuter if [ == "-h" ]et échouera car il ==n'a reçu qu'un seul argument lorsqu'il en attendait deux:
$ [=="-h"]
bash:[:==: unary operator expected
Pour toute utilisation plus complexe getoptougetopts
Comme suggéré par d' autres , si vous avez plus d'une seule option simple, ou si vous avez besoin de votre option pour accepter un argument, vous devez absolument opter pour la complexité supplémentaire de l'utilisation getopts.
Vous pouvez également envisager le getoptprogramme au lieu du shell intégré getopts. Il permet l'utilisation d'options longues et d'options après des arguments non optionnels (par exemple foo a b c --verboseplutôt que juste foo -v a b c). Cette réponse Stackoverflow explique comment utiliser GNU getopt.
Merci! J'utilise avec plaisir getopts depuis un an maintenant, mais je vais aussi jeter un œil à getopt.
tttppp
1
Malheureusement, le lien vers le didacticiel de 60 secondes getopts est mort; il semble que bashcurescancer.com n'existe plus. Voici un lien vers la version de Wayback Machine .
Réponses:
voici un exemple pour bash:
Pour utiliser ceci dans une fonction:
"$FUNCNAME"
au lieu de$(basename "$0")
local OPTIND OPTARG
avant d'appelergetopts
la source
basename
avec le tiret de tête."$FUNCNAME"
pas"$0"
. Aussi, ajouterlocal OPTIND OPTARG
FUNCNAME
travaux. J'ai toutes mes fonctions dans un seul fichier, c'est donc parfait pour les étendre en quelque chose d'utile pour les autres."$usage"
chaque endroit où vous l'utilisez.shift $((OPTIND - 1))
pour?Le premier argument d'un script shell est disponible comme variable
$1
, donc l'implémentation la plus simple seraitMais ce qu'a dit anubhava.
la source
[
version compatible POSIX.function
: vous devez remplacerexit 0
parreturn
si vous ne voulez pas terminer votre shell après avoir exécuté votre fonction. (Je l'ai fait avant 😂)voici une partie que je l'utilise pour démarrer un serveur VNC
C'est un peu bizarre que j'ai placé le redémarrage start stop dans un cas séparé mais cela devrait fonctionner
la source
Pour une solution rapide à option unique, utilisez
if
Si vous n'avez qu'une seule option à vérifier et que ce sera toujours la première option (
$1
), alors la solution la plus simple est uneif
avec un test ([
). Par exemple:Notez que pour posix, la compatibilité
=
fonctionnera aussi bien que==
.Pourquoi citer
$1
?La raison pour laquelle il
$1
faut mettre entre guillemets est que s'il n'y en a pas,$1
le shell essaiera de s'exécuterif [ == "-h" ]
et échouera car il==
n'a reçu qu'un seul argument lorsqu'il en attendait deux:Pour toute utilisation plus complexe
getopt
ougetopts
Comme suggéré par d' autres , si vous avez plus d'une seule option simple, ou si vous avez besoin de votre option pour accepter un argument, vous devez absolument opter pour la complexité supplémentaire de l'utilisation
getopts
.Comme référence rapide, j'aime le tutoriel getopts de 60 secondes . †
Vous pouvez également envisager le
getopt
programme au lieu du shell intégrégetopts
. Il permet l'utilisation d'options longues et d'options après des arguments non optionnels (par exemplefoo a b c --verbose
plutôt que justefoo -v a b c
). Cette réponse Stackoverflow explique comment utiliser GNUgetopt
.† Jeffbyrnes a mentionné que le lien original était mort mais heureusement, la machine de retour l' avait archivé.
la source
Mieux vaut utiliser la fonction getopt de bash. Veuillez consulter ces questions et réponses pour plus d'aide: Utilisation de getopts dans le script shell bash pour obtenir des options de ligne de commande longues et courtes
la source
Je pense que vous pouvez utiliser le cas pour cela ...
la source