Come gestisco le opzioni in uno script di shell?


17

Esistono alcuni strumenti integrati che riconoscono -xe --xxxxcome switch, e non argomenti, oppure devi esaminare tutte le variabili di input, verificare i trattini e analizzare successivamente gli argomenti?

Risposte:


16

Usa getopts.

È abbastanza portatile come nelle specifiche POSIX. Sfortunatamente non supporta opzioni lunghe.

Vedi anche questo getopts tutorial per gentile concessione della wiki di bash-hacker e questa domanda da StackOverflow.

Se sono necessarie solo opzioni brevi, il modello di utilizzo tipico per getopts(utilizzando la segnalazione 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

3
Va detto che getoptdovrebbe sempre essere verificato come GNU getopt prima di usarlo, ma non dovresti usarlo comunque poiché getoptsè più portatile (e generalmente più bello) comunque. Se fai bisogno di chiamarlo per qualche ragione, lo chiamano in un modo GNU-specifici, e assicurarsi che GETOPT_COMPATIBLEnon sia nell'ambiente.
Chris Down,

Cosa fanno i due punti while getopts "ab:" opt?
user394

1
@ user394 La :lettera dopo un'opzione indica che richiede un argomento. A :come primo carattere significa sopprimere i messaggi di errore.
jw013,

22

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[@]}" "$@"

1
+1 per l'utilizzo +=con un array. Non sapevo che potresti farlo. Bello!
James Sneeringer,

5

Devi scrivere un ciclo per analizzare i parametri. In effetti puoi usare il getoptscomando per farlo facilmente.

Questo è un semplice esempio dalla getoptspagina del 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" "$*"

2

Di recente ho scritto una sceneggiatura per un lavoro versatile che permettesse più tipi di switch in qualsiasi ordine. Non posso rivelare l'intero copione per ovvi motivi legali (per non parlare del fatto che non ce l'ho con me al momento), ma eccone il contenuto .. puoi metterlo in un sottoprogramma e chiamarlo alla fine della tua sceneggiatura:

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

Consiglio di limitare il tuo script bash a meno di 400 righe / 15k caratteri; la mia sceneggiatura di cui sopra è cresciuta oltre queste dimensioni ed è diventato molto difficile lavorarci su. Ho iniziato a riscriverlo in Perl, che è molto più adatto per l'attività. Tienilo a mente mentre lavori sui tuoi script in bash. Bash è ottimo per piccoli script e oneliner, ma qualcosa di più complesso e farai meglio a scriverlo in Perl.

Nota, non ho testato quanto sopra, quindi probabilmente non funziona, ma hai un'idea generale da esso.


Il modo in cui chiami optionsalla fine non è corretto, tornerà -bash: syntax error near unexpected token $@. Chiamalo come options "$@".
Chris Down,

Sì, ho confuso Perl e Bash. Corretto.
laebshade,

Quella whilecondizione non dovrebbe essere (($#))invece?
arte

Perché avresti bisogno di due serie di parentesi per $#? Modifica: hai ragione. Risolto il problema conwhile (( "$#" ))
laebshade,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.