Après plusieurs jours de recherche , je n'arrive toujours pas à trouver la meilleure méthode pour analyser les arguments cmdline dans un script .sh. Selon mes références, la cmd getopts est la voie à suivre car elle " extrait et vérifie les commutateurs sans perturber les variables de paramètre de position. Les commutateurs inattendus, ou les commutateurs qui manquent d'arguments, sont reconnus et signalés comme des erreurs. = "
Les paramètres positionnels (Ex. 2 - $ @, $ #, etc.) ne fonctionnent apparemment pas bien lorsque des espaces sont impliqués, mais peuvent reconnaître les paramètres réguliers et longs (-p et --longparam). J'ai remarqué que les deux méthodes échouent lors du passage de paramètres avec des guillemets imbriqués ("ceci est un Ex. De" "quotes" "."). Lequel de ces trois exemples de code illustre le mieux la manière de traiter les arguments cmdline? La fonction getopt n'est pas recommandée par les gourous, donc j'essaye de l'éviter!
Exemple 1:
#!/bin/bash
for i in "$@"
do
case $i in
-p=*|--prefix=*)
PREFIX=`echo $i | sed 's/[-a-zA-Z0-9]*=//'`
;;
-s=*|--searchpath=*)
SEARCHPATH=`echo $i | sed 's/[-a-zA-Z0-9]*=//'`
;;
-l=*|--lib=*)
DIR=`echo $i | sed 's/[-a-zA-Z0-9]*=//'`
;;
--default)
DEFAULT=YES
;;
*)
# unknown option
;;
esac
done
exit 0
Exemple 2:
#!/bin/bash
echo ‘number of arguments’
echo "\$#: $#"
echo ”
echo ‘using $num’
echo "\$0: $0"
if [ $# -ge 1 ];then echo "\$1: $1"; fi
if [ $# -ge 2 ];then echo "\$2: $2"; fi
if [ $# -ge 3 ];then echo "\$3: $3"; fi
if [ $# -ge 4 ];then echo "\$4: $4"; fi
if [ $# -ge 5 ];then echo "\$5: $5"; fi
echo ”
echo ‘using $@’
let i=1
for x in $@; do
echo "$i: $x"
let i=$i+1
done
echo ”
echo ‘using $*’
let i=1
for x in $*; do
echo "$i: $x"
let i=$i+1
done
echo ”
let i=1
echo ‘using shift’
while [ $# -gt 0 ]
do
echo "$i: $1"
let i=$i+1
shift
done
[/bash]
output:
bash> commandLineArguments.bash
number of arguments
$#: 0
using $num
$0: ./commandLineArguments.bash
using $@
using $*
using shift
#bash> commandLineArguments.bash "abc def" g h i j*
Exemple 3:
#!/bin/bash
while getopts ":a:" opt; do
case $opt in
a)
echo "-a was triggered, Parameter: $OPTARG" >&2
;;
\?)
echo "Invalid option: -$OPTARG" >&2
exit 1
;;
:)
echo "Option -$OPTARG requires an argument." >&2
exit 1
;;
esac
done
exit 0
Je trouve que l'utilisation de getopt
est la plus simple. Il fournit une gestion correcte des arguments, ce qui est autrement délicat. Par exemple, getopt
saura comment gérer les arguments d'une option longue spécifiée sur la ligne de commande comme --arg=option
ou --arg option
.
Ce qui est utile pour analyser toute entrée passée à un script Shell est l'utilisation du "$@"
variables. Reportez-vous à la page de manuel de bash pour savoir en quoi cela diffère de $@
. Cela garantit que vous pouvez traiter les arguments qui incluent des espaces.
Voici un exemple de la façon dont je pourrais écrire un script pour analyser quelques arguments de ligne de commande simples:
#!/bin/bash
args=$(getopt -l "searchpath:" -o "s:h" -- "$@")
eval set -- "$args"
while [ $# -ge 1 ]; do
case "$1" in
--)
# No more options left.
shift
break
;;
-s|--searchpath)
searchpath="$2"
shift
;;
-h)
echo "Display some help"
exit 0
;;
esac
shift
done
echo "searchpath: $searchpath"
echo "remaining args: $*"
Et utilisé comme ceci pour montrer que les espaces et les guillemets sont préservés:
user@machine:~/bin$ ./getopt_test --searchpath "File with spaces and \"quotes\"."
searchpath: File with spaces and "quotes".
remaining args: other args
Quelques informations de base sur l'utilisation de getopt
peuvent être trouvées ici
Si vous voulez éviter d'utiliser getopt
, vous pouvez utiliser cette approche rapide de Nice:
##
commentaires (personnaliser à votre guise).log.sh
#!/bin/sh
## $PROG 1.0 - Print logs [2017-10-01]
## Compatible with bash and dash/POSIX
##
## Usage: $PROG [OPTION...] [COMMAND]...
## Options:
## -i, --log-info Set log level to info (default)
## -q, --log-quiet Set log level to quiet
## -l, --log MESSAGE Log a message
## Commands:
## -h, --help Displays this help and exists
## -v, --version Displays output version and exists
## Examples:
## $PROG -i myscrip-simple.sh > myscript-full.sh
## $PROG -r myscrip-full.sh > myscript-simple.sh
PROG=${0##*/}
LOG=info
die() { echo $@ >&2; exit 2; }
log_info() {
LOG=info
}
log_quiet() {
LOG=quiet
}
log() {
[ $LOG = info ] && echo "$1"; return 1 ## number of args used
}
help() {
grep "^##" "$0" | sed -e "s/^...//" -e "s/\$PROG/$PROG/g"; exit 0
}
version() {
help | head -1
}
[ $# = 0 ] && help
while [ $# -gt 0 ]; do
CMD=$(grep -m 1 -Po "^## *$1, --\K[^= ]*|^##.* --\K${1#--}(?:[= ])" log.sh | sed -e "s/-/_/g")
if [ -z "$CMD" ]; then echo "ERROR: Command '$1' not supported"; exit 1; fi
shift; eval "$CMD" $@ || shift $? 2> /dev/null
done
Exécution de cette commande:
./log.sh --log yep --log-quiet -l nop -i -l yes
Produit cette sortie:
yep
yes
Au fait: C'est compatible avec posix !