Je veux concevoir un script Shell comme wrapper pour quelques scripts. Je voudrais spécifier les paramètres pour myshell.sh
en utilisant getopts
et transmettre les paramètres restants dans le même ordre au script spécifié.
Si myshell.sh
est exécuté comme:
myshell.sh -h hostname -s test.sh -d waittime param1 param2 param3
myshell.sh param1 param2 -h hostname param3 -d waittime -s test.sh
myshell.sh param1 -h hostname -d waittime -s test.sh param2 param3
Tout ce qui précède devrait pouvoir appeler en tant que
test.sh param1 param2 param3
Est-il possible d'utiliser les paramètres d'options dans myshell.sh
et de poster les paramètres restants dans le script sous-jacent?
Désolé de commenter un ancien fil de discussion, mais je pensais poster pour ceux qui, comme moi, cherchaient comment faire cela ...
Je voulais faire quelque chose de similaire au PO et j'ai trouvé les informations pertinentes dont j'avais besoin ici et ici
Essentiellement, si vous voulez faire quelque chose comme:
script.sh [options] ARG1 ARG2
Ensuite, obtenez vos options comme ceci:
while getopts "h:u:p:d:" flag; do
case "$flag" in
h) HOSTNAME=$OPTARG;;
u) USERNAME=$OPTARG;;
p) PASSWORD=$OPTARG;;
d) DATABASE=$OPTARG;;
esac
done
Et alors vous pouvez obtenir vos arguments de position comme ceci:
ARG1=${@:$OPTIND:1}
ARG2=${@:$OPTIND+1:1}
Plus d'informations et de détails sont disponibles via le lien ci-dessus.
J'espère que cela pourra aider!!
Mix opts et args:
ARGS=""
echo "options :"
while [ $# -gt 0 ]
do
unset OPTIND
unset OPTARG
while getopts as:c: options
do
case $options in
a) echo "option a no optarg"
;;
s) serveur="$OPTARG"
echo "option s = $serveur"
;;
c) cible="$OPTARG"
echo "option c = $cible"
;;
esac
done
shift $((OPTIND-1))
ARGS="${ARGS} $1 "
shift
done
echo "ARGS : $ARGS"
exit 1
Résultat:
bash test.sh -a arg1 arg2 -s serveur -c cible arg3
options :
option a no optarg
option s = serveur
option c = cible
ARGS : arg1 arg2 arg3
getopts
n'analysera pas le mélange des options param1
et -n
.
Il est bien mieux de mettre param1-3 dans des options comme les autres.
De plus, vous pouvez utiliser des bibliothèques déjà existantes telles que shflags . C'est très intelligent et facile à utiliser.
Et le dernier moyen consiste à écrire votre propre fonction pour analyser les paramètres sans getopts, en itérant tous les paramètres à travers la construction case
. C’est le moyen le plus difficile mais c’est le seul moyen de répondre exactement à vos attentes.
J'ai imaginé l'une des façons dont getopts
peut être étendu pour vraiment mélanger les options et les paramètres de position. L'idée est d'alterner entre l'appel getopts
et l'attribution des paramètres de position trouvés à n1
, n2
, n3
, etc.:
parse_args() {
_parse_args 1 "$@"
}
_parse_args() {
local n="$1"
shift
local options_func="$1"
shift
local OPTIND
"$options_func" "$@"
shift $(( OPTIND - 1 ))
if [ $# -gt 0 ]; then
eval test -n \${n$n+x}
if [ $? -eq 0 ]; then
eval n$n="\$1"
fi
shift
_parse_args $(( n + 1 )) "$options_func" "$@"
fi
}
Ensuite, dans le cas du PO, vous pourriez l'utiliser comme:
main() {
local n1='' n2='' n3=''
local duration hostname script
parse_args parse_main_options "$@"
echo "n1 = $n1"
echo "n2 = $n2"
echo "n3 = $n3"
echo "duration = $duration"
echo "hostname = $hostname"
echo "script = $script"
}
parse_main_options() {
while getopts d:h:s: opt; do
case "$opt" in
d) duration="$OPTARG" ;;
h) hostname="$OPTARG" ;;
s) script="$OPTARG" ;;
esac
done
}
main "$@"
En cours d'exécution, il affiche la sortie:
$ myshell.sh param1 param2 -h hostname param3 -d waittime -s test.sh
n1 = param1
n2 = param2
n3 = param3
duration = waittime
hostname = hostname
script = test.sh
Juste une preuve de concept, mais peut-être utile pour quelqu'un.
Remarque: il y a un casse-tête si une fonction qui utilise parse_args
appelle une autre fonction qui utilise parse_args
et la fonction externe déclare par exemple. local n4=''
, mais le paramètre interne pas et 4 ou plusieurs paramètres de position sont transmis à la fonction interne
Il suffit de réduire un quickie, qui gère facilement un mélange d'options et de paramètres de position (ne laissant que les paramètres de position dans $ @):
#!/bin/bash
while [ ${#} -gt 0 ];do OPTERR=0;OPTIND=1;getopts "p:o:hvu" arg;case "$arg" in
p) echo "Path: [$OPTARG]" ;;
o) echo "Output: [$OPTARG]" ;;
h) echo "Help" ;;
v) echo "Version" ;;
\?) SET+=("$1") ;;
*) echo "Coding error: '-$arg' is not handled by case">&2 ;;
esac;shift;[ "" != "$OPTARG" ] && shift;done
[ ${#SET[@]} -gt 0 ] && set "" "${SET[@]}" && shift
echo -e "=========\nLeftover (positional) parameters (count=$#) are:"
for i in `seq $#`;do echo -e "\t$i> [${!i}]";done
Exemple de sortie:
[root@hots:~]$ ./test.sh 'aa bb' -h -v -u -q 'cc dd' -p 'ee ff' 'gg hh' -o ooo
Help
Version
Coding error: '-u' is not handled by case
Path: [ee ff]
Output: [ooo]
=========
Leftover (positional) parameters (count=4) are:
1> [aa bb]
2> [-q]
3> [cc dd]
4> [gg hh]
[root@hots:~]$
Vous pouvez essayer cette astuce: après la boucle while avec optargs, utilisez simplement cet extrait.
#shift away all the options so that only positional agruments
#remain in $@
for (( i=0; i<OPTIND-1; i++)); do
shift
done
POSITIONAL="$@"
Cependant, cette approche a un bug:
Peut-être qu'il a encore plus de bugs ...
Regardez tout l'exemple:
while getopts :abc opt; do
case $opt in
a)
echo found: -a
;;
b)
echo found: -b
;;
c)
echo found: -c
;;
\?) echo found bad option: -$OPTARG
;;
esac
done
#OPTIND-1 now points to the first arguments not beginning with -
#shift away all the options so that only positional agruments
#remain in $@
for (( i=0; i<OPTIND-1; i++)); do
shift
done
POSITIONAL="$@"
echo "positional: $POSITIONAL"
Sortie:
[root@Host ~]# ./abc.sh -abc -de -fgh -bca haha blabla -m -c
found: -a
found: -b
found: -c
found bad option: -d
found bad option: -e
found bad option: -f
found bad option: -g
found bad option: -h
found: -b
found: -c
found: -a
positional: haha blabla -m -c
Il existe certaines normes pour le traitement des options Unix, et dans la programmation Shell, getopts
est le meilleur moyen de les appliquer. Presque tous les langages modernes (Perl, python) ont une variante sur getopts
.
Ceci est juste un exemple rapide:
command [ options ] [--] [ words ]
Chaque option doit commencer par un tiret, -
, et doit consister en un seul caractère.
Le projet GNU a introduit Long Options, en commençant par deux tirets --
, Suivi d'un mot entier, --long_option
. Le projet AST KSH comporte un getopts qui prend également en charge les options longues, et les options longues, commençant par un tiret unique, -
, comme dans find(1)
.
Les options peuvent ou ne peuvent pas attendre des arguments.
Tout mot ne commençant pas par un tiret, -
, mettra fin au traitement des options.
La chaîne --
doit être ignorée et mettra fin au traitement des options.
Tous les arguments restants sont laissés en tant que paramètres de position.
Le groupe ouvert a une section sur Utility Argument Syntax
L'art de la programmation Unix d'Eric Raymond a un chapitre sur les choix Unix traditionnels pour les lettres d'option et leur signification.