2542 Stimmen

Wie analysiere ich Kommandozeilenargumente in der Bash?

Angenommen, ich habe ein Skript, das mit dieser Zeile aufgerufen wird:

./myscript -vfd ./foo/bar/someFile -o /fizz/someOtherFile

oder dieses:

./myscript -v -f -d -o /fizz/someOtherFile ./foo/bar/someFile 

Wie kann man dies so interpretieren, dass in jedem Fall (oder einer Kombination von beiden) $v , $f y $d werden alle auf true y $outFile wird gleich sein mit /fizz/someOtherFile ?

1 Stimmen

Für zsh-Benutzer gibt es ein großartiges builtin namens zparseopts, das das kann: zparseopts -D -E -M -- d=debug -debug=d Und haben beide -d y --debug im $debug Array echo $+debug[1] gibt 0 oder 1 zurück, wenn einer dieser Werte verwendet wird. Ref: zsh.org/mla/users/2011/msg00350.html

2 Stimmen

Ein wirklich gutes Tutorial: linuxcommand.org/lc3_wss0120.php . Besonders gut gefällt mir das Beispiel "Befehlszeilenoptionen".

0 Stimmen

Ich habe ein Skript erstellt, das dies für Sie erledigt, es heißt - github.com/unfor19/bargs

3voto

Mihir Luthra Punkte 5000

Ich wollte mit Ihnen teilen, was ich für Parsing-Optionen gemacht habe. Einige meiner Bedürfnisse wurden von den Antworten hier nicht erfüllt, also musste ich mir das hier einfallen lassen: https://github.com/MihirLuthra/bash_option_parser

Dies unterstützt:

  • Unteroption parsen
  • Aliasnamen für Optionen
  • Optionale Argumente
  • Variable Argumente
  • Verwendung und Fehler beim Drucken

Nehmen wir an, wir haben einen Befehl namens fruit mit folgender Verwendung:

fruit <fruit-name> ...
   [-e|—-eat|—-chew]
   [-c|--cut <how> <why>]
   <command> [<args>] 

-e nimmt keine Argumente
-c benötigt zwei Argumente, nämlich wie und warum geschnitten werden soll
fruit selbst benötigt mindestens ein Argument.
<command> ist für Unteroptionen wie apple , orange usw. (ähnlich wie bei git mit den Unteroptionen commit , push usw. )

Um es also zu analysieren:

parse_options \
    'fruit'                         '1 ...'  \
    '-e'     , '--eat' , '--chew'   '0'      \
    '-c'     , '--cut'              '1 1'    \
    'apple'                         'S'      \
    'orange'                        'S'      \
    ';' \
    "$@"

Wenn nun ein Verwendungsfehler auftrat, kann dieser mit option_parser_error_msg wie folgt:

retval=$?

if [ $retval -ne 0 ]; then
    # this will manage error messages if
    # insufficient or extra args are supplied

    option_parser_error_msg "$retval"

    # This will print the usage
    print_usage 'fruit'
    exit 1
fi

Um nun zu prüfen, ob einige Optionen übergeben wurden,

if [ -n "${OPTIONS[-c]}" ]
then
    echo "-c was passed"

    # args can be accessed in a 2D-array-like format
    echo "Arg1 to -c = ${ARGS[-c,0]}"
    echo "Arg2 to -c = ${ARGS[-c,1]}"

fi

Das Parsen von Unteroptionen kann auch durch die Übergabe von $shift_count a parse_options_detailed was dazu führt, dass das Parsen nach dem Verschieben von args beginnt, um args der Unteroption zu erreichen. Dies wird in diesem Beispiel demonstriert Beispiel .

Eine ausführliche Beschreibung ist in der Readme-Datei und in den Beispielen enthalten in der Repository .

3voto

mjs Punkte 19667

Hier ist ein getopts, das das Parsing mit minimalem Code erreicht und Ihnen erlaubt, zu definieren, was Sie in einem Fall mit eval mit substring extrahieren möchten.

Grundsätzlich eval "local key='val'"

function myrsync() {

        local backup=("${@}") args=(); while [[ $# -gt 0 ]]; do k="$1";
                case "$k" in
                    ---sourceuser|---sourceurl|---targetuser|---targeturl|---file|---exclude|---include)
                        eval "local ${k:3}='${2}'"; shift; shift    # Past two arguments
                    ;;
                    *)  # Unknown option  
                        args+=("$1"); shift;                        # Past argument only
                    ;;                                              
                esac                                                
        done; set -- "${backup[@]}"                                 # Restore $@

        echo "${sourceurl}"
}

Deklariert die Variablen als lokale Variablen und nicht als globale Variablen, wie die meisten Antworten hier.

Aufgerufen als:

myrsync ---sourceurl http://abc.def.g ---sourceuser myuser ... 

Das ${k:3} ist im Grunde eine Teilzeichenkette zum Entfernen der ersten --- vom Schlüssel.

3voto

Emeric Verschuur Punkte 343

Ich habe einen Bash-Helper geschrieben, um ein nettes Bash-Tool zu schreiben

Projekt Heimat: https://gitlab.mbedsys.org/mbedsys/bashopts

Beispiel:

#!/bin/bash -ei

# load the library
. bashopts.sh

# Enable backtrace dusplay on error
trap 'bashopts_exit_handle' ERR

# Initialize the library
bashopts_setup -n "$0" -d "This is myapp tool description displayed on help message" -s "$HOME/.config/myapprc"

# Declare the options
bashopts_declare -n first_name -l first -o f -d "First name" -t string -i -s -r
bashopts_declare -n last_name -l last -o l -d "Last name" -t string -i -s -r
bashopts_declare -n display_name -l display-name -t string -d "Display name" -e "\$first_name \$last_name"
bashopts_declare -n age -l number -d "Age" -t number
bashopts_declare -n email_list -t string -m add -l email -d "Email adress"

# Parse arguments
bashopts_parse_args "$@"

# Process argument
bashopts_process_args

wird Hilfe leisten:

NAME:
    ./example.sh - This is myapp tool description displayed on help message

USAGE:
    [options and commands] [-- [extra args]]

OPTIONS:
    -h,--help                          Display this help
    -n,--non-interactive true          Non interactive mode - [$bashopts_non_interactive] (type:boolean, default:false)
    -f,--first "John"                  First name - [$first_name] (type:string, default:"")
    -l,--last "Smith"                  Last name - [$last_name] (type:string, default:"")
    --display-name "John Smith"        Display name - [$display_name] (type:string, default:"$first_name $last_name")
    --number 0                         Age - [$age] (type:number, default:0)
    --email                            Email adress - [$email_list] (type:string, default:"")

viel Spaß :)

0 Stimmen

Unter Mac OS X erhalte ich diese Meldung: ```` lib/bashopts.sh: Zeile 138: declare: -A: ungültige Option declare: usage: declare [-afFirtx] [-p] [name[=wert] ...] Fehler in lib/bashopts.sh:138. 'declare -x -A bashopts_optprop_name' wurde mit Status 2 beendet Aufrufbaum: 1: lib/controller.sh:4 source(...) Beendet mit Status 1 ```

0 Stimmen

Sie benötigen die Bash-Version 4, um dies zu nutzen. Auf Mac ist die Standardversion 3. Sie können Homebrew verwenden, um Bash 4 zu installieren.

3voto

Mark Fox Punkte 8397

Mischen von positions- und flaggenbasierten Argumenten

--param=arg (durch Gleichheitszeichen getrennt)

Freies Mischen von Flaggen zwischen Positionsargumenten:

./script.sh dumbo 127.0.0.1 --environment=production -q -d
./script.sh dumbo --environment=production 127.0.0.1 --quiet -d

kann mit einem recht knappen Ansatz erreicht werden:

# process flags
pointer=1
while [[ $pointer -le $# ]]; do
   param=${!pointer}
   if [[ $param != "-"* ]]; then ((pointer++)) # not a parameter flag so advance pointer
   else
      case $param in
         # paramter-flags with arguments
         -e=*|--environment=*) environment="${param#*=}";;
                  --another=*) another="${param#*=}";;

         # binary flags
         -q|--quiet) quiet=true;;
                 -d) debug=true;;
      esac

      # splice out pointer frame from positional list
      [[ $pointer -gt 1 ]] \
         && set -- ${@:1:((pointer - 1))} ${@:((pointer + 1)):$#} \
         || set -- ${@:((pointer + 1)):$#};
   fi
done

# positional remain
node_name=$1
ip_address=$2

--param arg (durch Leerzeichen getrennt)

Es ist normalerweise klarer, nicht zu mischen --flag=value y --flag value Stile.

./script.sh dumbo 127.0.0.1 --environment production -q -d

Dies ist ein wenig riskant zu lesen, ist aber immer noch gültig

./script.sh dumbo --environment production 127.0.0.1 --quiet -d

Quelle

# process flags
pointer=1
while [[ $pointer -le $# ]]; do
   if [[ ${!pointer} != "-"* ]]; then ((pointer++)) # not a parameter flag so advance pointer
   else
      param=${!pointer}
      ((pointer_plus = pointer + 1))
      slice_len=1

      case $param in
         # paramter-flags with arguments
         -e|--environment) environment=${!pointer_plus}; ((slice_len++));;
                --another) another=${!pointer_plus}; ((slice_len++));;

         # binary flags
         -q|--quiet) quiet=true;;
                 -d) debug=true;;
      esac

      # splice out pointer frame from positional list
      [[ $pointer -gt 1 ]] \
         && set -- ${@:1:((pointer - 1))} ${@:((pointer + $slice_len)):$#} \
         || set -- ${@:((pointer + $slice_len)):$#};
   fi
done

# positional remain
node_name=$1
ip_address=$2

3voto

schily Punkte 309

Beachten Sie, dass getopt(1) war ein kurzlebiger Fehler von AT&T.

getopt wurde 1984 geschaffen, aber bereits 1986 begraben, weil es nicht wirklich brauchbar war.

Ein Beweis für die Tatsache, dass getopt sehr veraltet ist, dass die getopt(1) man-Seite erwähnt noch "$*" 代わりに "$@" der Bourne-Shell im Jahr 1986 zusammen mit dem getopts(1) Shell-Builtin, um mit Argumenten mit Leerzeichen darin umzugehen.

Übrigens: Wenn Sie daran interessiert sind, lange Optionen in Shell-Skripten zu analysieren, könnte es von Interesse sein zu wissen, dass die getopt(3) Implementierung von libc (Solaris) und ksh93 wurde eine einheitliche Implementierung für lange Optionen hinzugefügt, die lange Optionen als Alias für kurze Optionen unterstützt. Dies bewirkt ksh93 und die Bourne Shell eine einheitliche Schnittstelle für lange Optionen zu implementieren über getopts .

Ein Beispiel für lange Optionen aus der Manpage der Bourne-Shell:

getopts "f:(file)(input-file)o:(output-file)" OPTX "$@"

zeigt, wie lange Options-Aliase sowohl in der Bourne Shell als auch in ksh93 verwendet werden können.

Siehe die Manpage einer aktuellen Bourne Shell:

http://schillix.sourceforge.net/man/man1/bosh.1.html

und die Manpage für getopt(3) von OpenSolaris:

http://schillix.sourceforge.net/man/man3c/getopt.3c.html

und schließlich die getopt(1)-Manualseite, um das veraltete $* zu überprüfen:

http://schillix.sourceforge.net/man/man1/getopt.1.html

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