552 Stimmen

Verwendung von getopts zur Verarbeitung langer und kurzer Befehlszeilenoptionen

Ich möchte Lang- und Kurzformen von Befehlszeilenoptionen haben, die über mein Shell-Skript aufgerufen werden.

Ich weiß, dass getopts verwendet werden, aber wie in Perl konnte ich das nicht mit der Shell machen.

Irgendwelche Ideen, wie dies geschehen kann, damit ich Optionen wie:

./shell.sh --copyfile abc.pl /tmp/
./shell.sh -c abc.pl /tmp/

Im obigen Beispiel bedeuten beide Befehle für meine Shell das Gleiche, aber mit getopts Ich habe es nicht geschafft, diese zu implementieren?

16voto

jakesandlund Punkte 401

Falls Sie nicht wollen, dass die getopt Abhängigkeit, können Sie dies tun:

while test $# -gt 0
do
  case $1 in

  # Normal option processing
    -h | --help)
      # usage and help
      ;;
    -v | --version)
      # version info
      ;;
  # ...

  # Special cases
    --)
      break
      ;;
    --*)
      # error unknown (long) option $1
      ;;
    -?)
      # error unknown (short) option $1
      ;;

  # FUN STUFF HERE:
  # Split apart combined short options
    -*)
      split=$1
      shift
      set -- $(echo "$split" | cut -c 2- | sed 's/./-& /g') "$@"
      continue
      ;;

  # Done with options
    *)
      break
      ;;
  esac

  # for testing purposes:
  echo "$1"

  shift
done

Natürlich können Sie dann keine langen Stiloptionen mit einem Bindestrich verwenden. Und wenn Sie verkürzte Versionen hinzufügen möchten (z. B. --verbos statt --verbose), müssen Sie diese manuell hinzufügen.

Aber wenn Sie auf der Suche sind nach getopts Funktionalität zusammen mit langen Optionen ist dies eine einfache Möglichkeit, dies zu tun.

Ich habe dieses Snippet auch in eine 主旨 .

12voto

Nietzche-jou Punkte 14185

Die eingebaute getopts kann das nicht tun. Es gibt eine externe getopt (1) Programm, das dies kann, aber man bekommt es unter Linux nur von der util-linux Paket. Es wird mit einem Beispielskript geliefert getopt-parse.bash .

Außerdem gibt es eine getopts_long als Shell-Funktion geschrieben.

9voto

UrsaDK Punkte 764

Die akzeptierte Antwort weist sehr schön auf alle Unzulänglichkeiten der eingebauten Bash hin getopts . Die Antwort endet mit:

Es ist zwar möglich, mehr Code zu schreiben, um die fehlende Unterstützung für lange Optionen zu umgehen, aber das ist viel mehr Arbeit und verfehlt teilweise den Zweck der Verwendung eines getopt-Parsers zur Vereinfachung Ihres Codes.

Und obwohl ich dieser Aussage grundsätzlich zustimme, bin ich der Meinung, dass die Anzahl der von uns allen in verschiedenen Skripten implementierten Funktionen es rechtfertigt, ein wenig Aufwand in die Schaffung einer "standardisierten", gut getesteten Lösung zu investieren.

Daher habe ich die Bash "aufgerüstet", die in getopts durch die Umsetzung getopts_long in reiner Bash, ohne externe Abhängigkeiten. Die Verwendung der Funktion ist 100% kompatibel mit der eingebauten getopts .

Durch die Einbeziehung getopts_long (das ist gehostet auf GitHub ) in ein Skript einfügen, kann die Antwort auf die ursprüngliche Frage so einfach wie folgt implementiert werden:

source "${PATH_TO}/getopts_long.bash"

while getopts_long ':c: copyfile:' OPTKEY; do
    case ${OPTKEY} in
        'c'|'copyfile')
            echo 'file supplied -- ${OPTARG}'
            ;;
        '?')
            echo "INVALID OPTION -- ${OPTARG}" >&2
            exit 1
            ;;
        ':')
            echo "MISSING ARGUMENT for option -- ${OPTARG}" >&2
            exit 1
            ;;
        *)
            echo "Misconfigured OPTSPEC or uncaught option -- ${OPTKEY}" >&2
            exit 1
            ;;
    esac
done

shift $(( OPTIND - 1 ))
[[ "${1}" == "--" ]] && shift

9voto

3ED Punkte 115
#!/bin/bash
while getopts "abc:d:" flag
do
  case $flag in
    a) echo "[getopts:$OPTIND]==> -$flag";;
    b) echo "[getopts:$OPTIND]==> -$flag";;
    c) echo "[getopts:$OPTIND]==> -$flag $OPTARG";;
    d) echo "[getopts:$OPTIND]==> -$flag $OPTARG";;
  esac
done

shift $((OPTIND-1))
echo "[otheropts]==> $@"

exit

.

#!/bin/bash
until [ -z "$1" ]; do
  case $1 in
    "--dlong")
      shift
      if [ "${1:1:0}" != "-" ]
      then
        echo "==> dlong $1"
        shift
      fi;;
    *) echo "==> other $1"; shift;;
  esac
done
exit

8voto

Richard Lynch Punkte 71

Sur ksh93 , getopts unterstützt lange Namen...

while getopts "f(file):s(server):" flag
do
    echo "$flag" $OPTIND $OPTARG
done

So steht es zumindest in den Tutorials, die ich gefunden habe. Versuchen Sie es und sehen.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X