Esistono strumenti integrati in grado di riconoscere -x
e --xxxx
come opzioni e non argomenti, oppure devi esaminare tutte le variabili di input, verificare i trattini e quindi analizzare gli argomenti in seguito?
Risposta
Utilizza getopts
.
È abbastanza portatile come nelle specifiche POSIX. Sfortunatamente non supporta opzioni lunghe.
Vedi anche questo getopts
tutorial per gentile concessione di il wiki di bash-hackers e questa domanda da stackoverflow.
Se hai bisogno solo di opzioni brevi, modello di utilizzo tipico per getopts
(utilizzando la segnalazione degli errori non silenziosa) è:
# process arguments "$1", "$2", ... (i.e. "$@") while getopts "ab:" opt; do case $opt in a) aflag=true ;; # Handle -a b) barg=$OPTARG ;; # Handle -b argument \?) ;; # Handle error: unknown option or missing required argument. esac done
Commenti
- Va detto che
getopt
dovrebbe sempre essere verificato come GNU getopt prima di usarlo, ma non dovresti ' usarlo comunque poichégetopts
è comunque più portabile (e generalmente più carino). Se devi chiamarlo per qualche motivo, chiamalo in un modo specifico per GNU, e assicurati cheGETOPT_COMPATIBLE
non si trovi nellambiente. - Che cosa fanno i due punti in
while getopts "ab:" opt
? - @ user394 Il
:
dopo una lettera di opzione lo indica richiede un argomento. Un:
come primo carattere significa sopprimere i messaggi di errore.
Risposta
Presumo che tu stia usando bash o simili. Un esempio:
all=false long=false while getopts ":hal" option; do case $option in h) echo "usage: $0 [-h] [-a] [-l] file ..."; exit ;; a) all=true ;; l) long=true ;; ?) echo "error: option -$OPTARG is not implemented"; exit ;; esac done # remove the options from the positional parameters shift $(( OPTIND - 1 )) ls_opts=() $all && ls_opts+=( -a ) $long && ls_opts+=( -l ) # now, do it ls "${ls_opts[@]}" "$@"
Commenti
Risposta
Devi scrivere un ciclo per analizzare i parametri. Infatti puoi usare getopts
per farlo facilmente.
Questo è un semplice esempio tratto dalla getopts
pagina di manuale:
aflag= bflag= while getopts ab: name do case $name in a) aflag=1;; b) bflag=1 bval="$OPTARG";; ?) printf "Usage: %s: [-a] [-b value] args\n" $0 exit 2;; esac done if [ ! -z "$aflag" ]; then printf "Option -a specified\n" fi if [ ! -z "$bflag" ]; then printf "Option -b "%s" specified\n" "$bval" fi shift $(($OPTIND - 1)) printf "Remaining arguments are: %s\n" "$*"
Answer
Di recente ho scritto uno script per il lavoro che era versatile e consentiva più tipi di interruttori in qualsiasi ordine. Non posso “t divulgare la sceneggiatura completa per ovvie ragioni legali (per non parlare del fatto che al momento non ce lho con me), ma ecco il nocciolo della questione .. puoi metterlo in n una subroutine e chiamala alla fine del tuo script:
options () { if [ -n "$1" ]; then # test if any arguments passed - $1 will always exist while (( "$#" )); do # process ALL arguments if [ "$1" = ^-t$ ]; then # -t short for "test" # do something here THEN shift the argument # shift removes it from $@ and reduces $# by # one if you supply no argument shift # we can also process multiple arguments at once elif [[ "$1" =~ ^--test=[:alnum:]{1,8}$ ]] && [[ "$2" =~ ^-t2$ ]] && [[ -n "$3" ]]; then # check for 3 arguments # do something more then remove them ALL from the arg list shift 3 else echo "No matching arguments!" echo "Usage: [script options list here]" fi done else echo "Usage: [script options list here]" exit 0 fi } options "$@" # run options and loop through/process ALL arguments
Raccomando di limitare il tuo script bash a meno di 400 righe / 15k caratteri; il mio script di cui sopra è cresciuto oltre questa dimensione ed è diventato molto difficile da lavorare. Ho iniziato a riscriverlo in Perl, che è molto più adatto per il compito. Tienilo a mente mentre lavori sui tuoi script in bash. Bash è ottimo per piccoli script e oneliner, ma qualsiasi cosa più complessa e faresti meglio a scriverlo in Perl.
Nota, non ho testato quanto sopra, quindi probabilmente non funziona, ma ne ricavi lidea generale.
Commenti
- Il modo in cui chiami
options
alla fine non è corretto, restituirà-bash: syntax error near unexpected token $@
. Chiamalooptions "$@"
. - Sì, ho mescolato Perl e Bash. Corretto.
- Quella
while
condizione non dovrebbe essere(($#))
? - Perché avresti bisogno di due serie di parentesi per
$#
? Modifica: ' hai ragione. Risolto il problema conwhile (( "$#" ))
+=
con un array. ' non sapevo che potevi farlo. Bello!