Come gestire la fine delle opzioni - in getopts


9

Uso getopts per analizzare gli argomenti negli script bash come

while getopts ":hd:" opt; do
  case $opt in
    d ) echo "directory = $OPTARG"; mydir="$OPTARG"; shift $((OPTIND-1)); OPTIND=1 ;;
    h ) helptext
      graceful_exit ;;
    * ) usage
      clean_up
      exit 1
  esac
done

exeparams="$*"

exeparamsconterrà eventuali opzioni / argomenti non analizzati. Dato che voglio usare exeparams per contenere le opzioni per l'esecuzione di un comando all'interno dello script (che può sovrapporsi alle opzioni proprie degli script), voglio usare - per terminare le opzioni passate allo script. Se passo ad es

myscript -d myscriptparam -- -d internalparam

exeparams terrà

-- -d internalparam

Ora voglio rimuovere il --comando principale per passare questi argomenti al comando interno. Esiste un modo elegante per farlo o posso ottenere una stringa che contiene solo il resto senza --getopts?


Mettere shift; OPTIND=1all'interno del getoptsloop non è probabilmente il modo migliore per farlo. Funziona solo nel tuo caso perché hai solo 2 opzioni e in tutte le altre hai appena lasciato lo script. Altrimenti avresti bisogno shift; OPTIND=1in ogni opzione, il che significa codice duplicato (cattiva pratica). Basta fare shift $((OPTIND - 1))subito dopo la fine del ciclo: questo è il modo più convenzionale e probabilmente anche il più efficiente.
jw013,

Risposte:


7

Che ne dite di:

# ... getopts processing ...

[[ $1 = "--" ]] && shift
exeparams=("$@")

Nota, è necessario utilizzare un array per contenere i parametri. Questo gestirà correttamente qualsiasi argomento contenente spazi bianchi. Dereference l'array con"${exeparams[@]}"


1
Ciò presuppone che non vi siano argomenti tra la fine delle opzioni e --, quindi script foo -- bar, passerebbe foo -- baral programma esterno. La mia risposta non fa questo presupposto in quanto non è stato esplicitamente dichiarato nella domanda.
jw013,

Tranne dove l'OP dice "Ora voglio rimuovere il leader -"
glenn jackman,

Questo era per l'esempio -- -d internalparams. In ogni caso la mia risposta è abbastanza generale da gestire entrambi i casi.
jw013,

14

Usa il built-in shift. Innanzitutto, fai il normale getoptsper la tua sceneggiatura. Una volta completato quel ciclo,

shift "$((OPTIND - 1))"

sposterà tutte le opzioni già elaborate.

Da lì, dovrai completare l'elaborazione degli argomenti non-option, se presenti, nella prima parte dello script (prima di --). Quando si incontra il --, spostarlo fino a quando rimane solo l'ultima parte (la -d internalparamparte che viene dopo --). Un modo per farlo (usando la bashsintassi):

while [[ $# -gt 0 ]]; do
    # process next argument
    case $1 in
    foo) # process foo
    ;;
    --) shift; break;; # found '--', discard it and exit loop
    *) # handle unrecognized argument
    ;;
    esac
    # not '--', so discard the argument and continue
    shift
done

Infine, rimane solo la seconda serie di opzioni / argomenti, che è possibile trasmettere. Da non usare $*per passare i restanti parametri di un altro comando. Usa "$@"invece, che conserva la suddivisione della parola originale.

external_command "$@"

Sì grazie! Ma come trovo esattamente --?
highsciguy
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.