2013-02-09 16 views
9

Nach mehreren Tagen von research kann ich immer noch nicht die beste Methode zum Parsen von cmdline args in einem .sh-Skript herausfinden. Nach meinen Referenzen die getopts cmd die Art und Weise, da es zu gehen „Extrakte und prüft, schaltet den Positionsparameter variables.Unexpected Schalter ohne Störung oder Schaltern, die Argumente fehlen, werden erkannt und reportedas Fehler.Die beste Methode zum Parsen von Befehlszeilenargumenten in Bash?

Positional Parameter (Bsp. 2 - $ @, $ #, usw.) funktionieren anscheinend nicht gut, wenn Leerzeichen involviert sind, können aber reguläre und lange Parameter (-p und --longparam) erkennen. Ich habe festgestellt, dass beide Methoden fehlschlagen, wenn Parameter mit verschachtelten Anführungszeichen übergeben werden ("das ist ein Beispiel von" "Anführungszeichen" "."). Welches dieser drei Codebeispiele zeigt am besten, wie man mit Befehlszeilen umgehen kann? Die getopt Funktion wird nicht von Gurus empfohlen, also versuche ich es zu vermeiden!

Beispiel 1:

#!/bin/bash 
for i in "[email protected]" 
do 
case $i in 
    -p=*|--prefix=*) 
    PREFIX=`echo $i | sed 's/[-a-zA-Z0-9]*=//'` 

    ;; 
    -s=*|--searchpath=*) 
    SEARCHPATH=`echo $i | sed 's/[-a-zA-Z0-9]*=//'` 
    ;; 
    -l=*|--lib=*) 
    DIR=`echo $i | sed 's/[-a-zA-Z0-9]*=//'` 
    ;; 
    --default) 
    DEFAULT=YES 
    ;; 
    *) 
      # unknown option 
    ;; 
esac 
done 
exit 0 

Beispiel 2:

#!/bin/bash 
echo ‘number of arguments’ 
echo "\$#: $#" 
echo ” 

echo ‘using $num’ 
echo "\$0: $0" 
if [ $# -ge 1 ];then echo "\$1: $1"; fi 
if [ $# -ge 2 ];then echo "\$2: $2"; fi 
if [ $# -ge 3 ];then echo "\$3: $3"; fi 
if [ $# -ge 4 ];then echo "\$4: $4"; fi 
if [ $# -ge 5 ];then echo "\$5: $5"; fi 
echo ” 

echo ‘using [email protected]’ 
let i=1 
for x in [email protected]; do 
echo "$i: $x" 
let i=$i+1 
done 
echo ” 

echo ‘using $*’ 
let i=1 
for x in $*; do 
echo "$i: $x" 
let i=$i+1 
done 
echo ” 

let i=1 
echo ‘using shift’ 
while [ $# -gt 0 ] 
do 
echo "$i: $1" 
let i=$i+1 
shift 
done 

[/bash] 

output: 

bash> commandLineArguments.bash 
number of arguments 
$#: 0 

using $num 
$0: ./commandLineArguments.bash 

using [email protected] 

using $* 

using shift 
#bash> commandLineArguments.bash "abc def" g h i j* 

Beispiel 3:

#!/bin/bash 

while getopts ":a:" opt; do 
    case $opt in 
    a) 
     echo "-a was triggered, Parameter: $OPTARG" >&2 
     ;; 
    \?) 
     echo "Invalid option: -$OPTARG" >&2 
     exit 1 
     ;; 
    :) 
     echo "Option -$OPTARG requires an argument." >&2 
     exit 1 
     ;; 
    esac 
done 

exit 0 
+1

mögliche Duplikate von [Wie parse ich Befehlszeilenargumente in bash?] (Http://stackoverflow.com/questions/192249/how-do-i-parse-command-line-arguments-in-bash) –

Antwort

18

Ich finde die Verwendung von getopt, um der einfachste zu sein. Es bietet eine korrekte Handhabung von Argumenten, was ansonsten schwierig ist. Zum Beispiel wird getopt wissen, wie mit Argumenten zu einer langen Option umzugehen ist, die in der Befehlszeile als oder --arg option angegeben wird.

Was beim Analysieren von Eingaben, die an ein Shell-Skript übergeben werden, nützlich ist, ist die Verwendung der Variablen "[email protected]". Auf der bash man-Seite finden Sie Informationen dazu, wie sich dies von [email protected] unterscheidet. Es stellt sicher, dass Sie Argumente verarbeiten können, die Leerzeichen enthalten.

Hier ist ein Beispiel dafür, wie ich s Skript schreiben könnte einige einfache Kommandozeilen-Argumente zu analysieren:

#!/bin/bash 

args=$(getopt -l "searchpath:" -o "s:h" -- "[email protected]") 

eval set -- "$args" 

while [ $# -ge 1 ]; do 
     case "$1" in 
       --) 
        # No more options left. 
        shift 
        break 
        ;; 
       -s|--searchpath) 
         searchpath="$2" 
         shift 
         ;; 
       -h) 
         echo "Display some help" 
         exit 0 
         ;; 
     esac 

     shift 
done 

echo "searchpath: $searchpath" 
echo "remaining args: $*" 

Und so benutzten zu zeigen, dass Räume und Zitate sind erhalten: Einige

[email protected]:~/bin$ ./getopt_test --searchpath "File with spaces and \"quotes\"." 
searchpath: File with spaces and "quotes". 
remaining args: other args 

Grundlegende Informationen über die Verwendung von getopt finden Sie here

+2

Das ist ein gutes Beispiel für getopt Austin. Dieses spezielle Thema wurde ausführlich in [stackoverflow] (http://stackoverflow.com/questions/402377/using-getopts-in-bash-shell-script-to-get-long-and-short-command-line-) diskutiert. Optionen/7680682 # 7680682). Der Unterschied ist einfach alt getopt ist nicht so robust wie getopts und funktioniert nicht auf älteren Systemen. Getopts können lange Switches parsen, solange es eine kurze Version desselben Switches gibt, also muss man etwas optimieren. Ich bleibe bei Getopts. Ich benutze lieber eine eingebaute Funktion als alte Exec (getopt) für professionelle Skripte. – LogicalConfusion

0

Wenn Sie vermeiden möchten, getopt Sie ca verwenden n Verwenden Sie diese nette, schnelle Methode:
- Definieren Sie Hilfe mit allen Optionen als ## Kommentare (anpassen, wie Sie möchten);
- Definieren Sie für jede Option eine Funktion mit demselben Namen;
- Kopieren Sie die letzten fünf Zeilen dieses Skripts in Ihr Skript (die Magie).

Beispiel: Protokoll. sh

#!/bin/sh 
## $PROG 1.0 - Print logs [2017-10-01] 
## Compatible with bash and dash/POSIX 
## 
## Usage: $PROG [OPTION...] [COMMAND]... 
## Options: 
## -i, --log-info   Set log level to info (default) 
## -q, --log-quiet  Set log level to quiet 
## -l, --log MESSAGE  Log a message 
## Commands: 
## -h, --help    Displays this help and exists 
## -v, --version   Displays output version and exists 
## Examples: 
## $PROG -i myscrip-simple.sh > myscript-full.sh 
## $PROG -r myscrip-full.sh > myscript-simple.sh 
PROG=${0##*/} 
LOG=info 
die() { echo [email protected] >&2; exit 2; } 

log_info() { 
    LOG=info 
} 
log_quiet() { 
    LOG=quiet 
} 
log() { 
    [ $LOG = info ] && echo "$1"; return 1 ## number of args used 
} 
help() { 
    grep "^##" "$0" | sed -e "s/^...//" -e "s/\$PROG/$PROG/g"; exit 0 
} 
version() { 
    help | head -1 
} 

[ $# = 0 ] && help 
while [ $# -gt 0 ]; do 
    CMD=$(grep -m 1 -Po "^## *$1, --\K[^= ]*|^##.* --\K${1#--}(?:[= ])" go.sh | sed -e "s/-/_/g") 
    if [ -z "$CMD" ]; then echo "ERROR: Command '$1' not supported"; exit 1; fi 
    shift; eval "$CMD" [email protected] || shift $? 2> /dev/null 
done 

Testing:

./log.sh --log yep --log-quiet -l nop -i -l yes produzieren:

yep 
yes 

By the way: Es ist kompatibel mit POSIX!

Verwandte Themen