Wie man mit dem Ende von Optionen umgeht - in getopts

9

Ich benutze getopts, um Argumente in Bash-Skripten als zu analysieren

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="$*"

exeparamsenthält alle nicht analysierten Optionen / Argumente. Da ich exeparams verwenden möchte, um Optionen für einen Befehl zu speichern, der innerhalb des Skripts ausgeführt werden soll (was sich mit den eigenen Optionen des Skripts überschneiden kann), möchte ich verwenden, um die an das Skript übergebenen Optionen zu beenden. Wenn ich z

myscript -d myscriptparam -- -d internalparam

exeparams wird halten

-- -d internalparam

Ich möchte jetzt die führende entfernen --, um diese Argumente an den internen Befehl zu übergeben. Gibt es eine elegante Möglichkeit, dies zu tun, oder kann ich eine Zeichenfolge erhalten, die nur den Rest ohne --Getopts enthält?

Highsciguy
quelle
Das Einfügen shift; OPTIND=1in die getoptsSchleife ist wahrscheinlich nicht der beste Weg, dies zu tun. Dies funktioniert nur in Ihrem Fall, da Sie nur zwei Optionen haben und in allen anderen nur das Skript beenden. Andernfalls würden Sie shift; OPTIND=1in jeder Option benötigen , was doppelten Code bedeutet (schlechte Praxis). Machen Sie einfach eine shift $((OPTIND - 1))unmittelbar nach dem Ende der Schleife - dies ist der konventionellste und wahrscheinlich auch der effizienteste Weg.
jw013

Antworten:

7

Wie wäre es mit:

# ... getopts processing ...

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

Beachten Sie, dass Sie ein Array verwenden sollten, um die Parameter zu speichern. Dadurch werden alle Argumente, die Leerzeichen enthalten, ordnungsgemäß behandelt. Dereferenzieren Sie das Array mit"${exeparams[@]}"

Glenn Jackman
quelle
1
Dies setzt voraus , dass es keine Argumente zwischen dem Ende der Optionen und --, also script foo -- barwürde passieren foo -- baran das externe Programm. Meine Antwort macht diese Annahme nicht, da sie in der Frage nicht explizit angegeben wurde.
jw013
Außer wo das OP sagt "Ich möchte jetzt den führenden -"
Glenn Jackman
Das war für das Beispiel -- -d internalparams. In jedem Fall ist meine Antwort allgemein genug, um beide Fälle zu behandeln.
jw013
14

Verwenden Sie das eingebaute shift. Führen Sie zunächst das Normale getoptsfür Ihr Skript aus. Sobald diese Schleife abgeschlossen ist,

shift "$((OPTIND - 1))"

verschiebt alle bereits verarbeiteten Optionen.

Von dort aus müssen Sie die Verarbeitung der Nichtoptionsargumente (falls vorhanden) bis zum ersten Teil des Skripts (vor dem --) abschließen. Sobald Sie auf das stoßen --, verschieben Sie es heraus, bis nur der letzte Teil übrig bleibt (der -d internalparamTeil, der danach kommt --). Eine Möglichkeit, dies zu tun (unter Verwendung der bashSyntax):

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

Schließlich bleibt nur der zweite Satz von Optionen / Argumenten übrig, den Sie weitergeben können. Verwenden Sie diese Option NICHT$* , um die verbleibenden Parameter an einen anderen Befehl zu übergeben. Verwenden Sie "$@"stattdessen, wodurch die ursprüngliche Wortaufteilung erhalten bleibt.

external_command "$@"
jw013
quelle
Ja dank! Aber wie genau finde ich --?
Highsciguy