Übergabe benannter Argumente an Shell-Skripte


114

Gibt es eine einfache Möglichkeit, benannte Parameter an ein Shell-Skript zu übergeben (zu empfangen)?

Zum Beispiel,

my_script -p_out '/some/path' -arg_1 '5'

Und im Inneren my_script.sherhalten sie als:

# I believe this notation does not work, but is there anything close to it?
p_out=$ARGUMENTS['p_out']
arg1=$ARGUMENTS['arg_1']

printf "The Argument p_out is %s" "$p_out"
printf "The Argument arg_1 is %s" "$arg1"

Ist das in Bash oder Zsh möglich?


2
haben einen Blick auf docopt - es hilft mit benannten Parametern und nicht Validierung Eingang auch
Schlagen

Antworten:


34

Die wahrscheinlich nächstliegende Syntax lautet:

p_out='/some/path' arg_1='5' my_script

7
Wenn die -kOption in der aufrufenden Shell festgelegt ist, my_script p_out='/some/path' arg_1='5'hat dies den gleichen Effekt. (Alle Argumente in Form einer Zuweisung werden der Umgebung hinzugefügt, nicht nur die Zuweisungen vor dem Befehl.)
Chepner

13
Früher habe ich diese Syntax geliebt, aber sie hat eine GROSSE Einschränkung: Nach der Ausführung von Befehlen / Funktionen werden diese Variablen immer noch im aktuellen Gültigkeitsbereich definiert! ZB: x=42 echo $x; echo $xWas bedeutet, dass bei der nächsten Ausführung von my_script, wenn p_outweggelassen, der beim letzten Mal übergebene Wert beibehalten wird !! ( '/some/path')
Lucas Cimon

@LucasCimon Kannst du sie nicht unsetnach der ersten Ausführung zurücksetzen, bevor die nächste Ausführung?
Nikos Alexandris

2
@LucasCimon Das ist nicht richtig. x=42 echo $xgibt nicht einmal etwas aus, wenn $xes vorher nicht definiert wurde.
Hauke ​​Laging

Du hast Recht @HaukeLaging, danke, dass du das korrigiert hast
Lucas Cimon

148

Wenn es Ihnen nichts ausmacht, sich auf Argumentnamen mit nur einem Buchstaben zu beschränken, können my_script -p '/some/path' -a5Sie in bash die eingebaute Funktion verwenden getopts, z

#!/bin/bash

while getopts ":a:p:" opt; do
  case $opt in
    a) arg_1="$OPTARG"
    ;;
    p) p_out="$OPTARG"
    ;;
    \?) echo "Invalid option -$OPTARG" >&2
    ;;
  esac
done

printf "Argument p_out is %s\n" "$p_out"
printf "Argument arg_1 is %s\n" "$arg_1"

Dann kannst du machen

$ ./my_script -p '/some/path' -a5
Argument p_out is /some/path
Argument arg_1 is 5

Es gibt ein hilfreiches kleines getopts-Tutorial, oder Sie können es help getoptsan der Shell-Eingabeaufforderung eingeben .


25
Dies sollte die akzeptierte Antwort sein
Kaushik Ghose

3
Ich weiß, das ist ein bisschen alt, aber warum nur 1 Buchstabe für die Argumente?
Kevin

1
Ich habe dies implementiert (aber mit iund d). Wenn ich es mit my_script -i asd -d asdstarte, bekomme ich eine leere Zeichenkette für das dArgument. Wenn ich es laufen my_script -d asd -i asdlasse, erhalte ich leere Zeichenkette für beide Argumente.
Milkncookiez

3
@ Milkncookiez - Ich hatte ein ähnliches Problem - Ich habe nach dem letzten Argument kein ':' eingefügt (ein 'w' in meinem Fall). Nachdem ich das ':' hinzugefügt hatte, fing es an, wie erwartet zu funktionieren
Derek

37

Ich habe dies von drupal.org gestohlen , aber Sie könnten so etwas tun:

while [ $# -gt 0 ]; do
  case "$1" in
    --p_out=*)
      p_out="${1#*=}"
      ;;
    --arg_1=*)
      arg_1="${1#*=}"
      ;;
    *)
      printf "***************************\n"
      printf "* Error: Invalid argument.*\n"
      printf "***************************\n"
      exit 1
  esac
  shift
done

Der einzige Nachteil ist, dass Sie die Syntax verwenden müssen my_script --p_out=/some/path --arg_1=5.


7
Die Einschränkung ist nicht erforderlich. :) Sie können die Bedingungen wie folgt haben:-c|--condition)
Milkncookiez

28

Ich benutze dieses Skript und arbeite wie ein Zauber:

for ARGUMENT in "$@"
do

    KEY=$(echo $ARGUMENT | cut -f1 -d=)
    VALUE=$(echo $ARGUMENT | cut -f2 -d=)   

    case "$KEY" in
            STEPS)              STEPS=${VALUE} ;;
            REPOSITORY_NAME)    REPOSITORY_NAME=${VALUE} ;;     
            *)   
    esac    


done

echo "STEPS = $STEPS"
echo "REPOSITORY_NAME = $REPOSITORY_NAME"

Verwendungszweck

bash my_scripts.sh  STEPS="ABC" REPOSITORY_NAME="stackexchange"

Konsolenergebnis:

STEPS = ABC
REPOSITORY_NAME = stackexchange

STEPS und REPOSITORY_NAME können jetzt im Skript verwendet werden.

Es spielt keine Rolle, in welcher Reihenfolge die Argumente stehen.


4
Dies ist ordentlich und sollte die akzeptierte Antwort sein.
Miguelmorin

15

Mit würden zshSie verwenden zparseopts:

#! /bin/zsh -
zmodload zsh/zutil
zparseopts -A ARGUMENTS -p_out: -arg_1:

p_out=$ARGUMENTS[--p_out]
arg1=$ARGUMENTS[--arg_1]

printf 'Argument p_out is "%s"\n' "$p_out"
printf 'Argument arg_1 is "%s"\n' "$arg_1"

Aber Sie würden das Skript mit aufrufen myscript --p_out foo.

Beachten Sie, dass zparseoptses nicht möglich ist, lange Optionen oder die --p_out=fooSyntax von GNU abzukürzen getopt(3).


Wissen Sie, warum die zparseopts nur einen Gedankenstrich für die Argumente verwenden, während es in der []2 Gedankenstriche sind? Macht keinen Sinn!
Timo

@ Timo, siehe info zsh zparseoptsfür Details
Stéphane Chazelas

9

Ich habe mir gerade dieses Skript ausgedacht

while [ $# -gt 0 ]; do

   if [[ $1 == *"--"* ]]; then
        v="${1/--/}"
        declare $v="$2"
   fi

  shift
done

übergeben Sie es wie my_script --p_out /some/path --arg_1 5und dann im Skript können Sie $arg_1und verwenden $p_out.


Ich mag diese Lösung in KSH88 Ich musste v=``echo ${1} | awk '{print substr($1,3)}'`` typeset $v="$2"(Entfernen Sie ein Backtick pro Seite)
hol

-2

Wenn eine Funktion oder eine Anwendung mehr als null Argumente hat, hat sie immer ein letztes Argument.

Wenn Sie Optionsflag- und Wertepaare lesen möchten, wie in: $ ./t.sh -o output -i input -l last

Und Sie möchten eine variable Anzahl von Option / Wert-Paaren akzeptieren,

Und will keinen riesigen "wenn ... dann ... sonst ... fi" -Baum,

Nachdem Sie auf eine Argumentanzahl ungleich Null und gerade geprüft haben,

Schreiben Sie eine while-Schleife mit diesen vier eval-Anweisungen als Rumpf, gefolgt von einer case-Anweisung mit den beiden Werten, die bei jedem Durchlauf der Schleife ermittelt werden.

Der knifflige Teil des Skripts wird hier gezeigt:

#!/bin/sh    

# For each pair - this chunk is hard coded for the last pair.
eval TMP="'$'$#"
eval "PICK=$TMP"
eval TMP="'$'$(($#-1))"
eval "OPT=$TMP"

# process as required - usually a case statement on $OPT
echo "$OPT \n $PICK"

# Then decrement the indices (as in third eval statement) 

:<< EoF_test
$ ./t.sh -o output -i input -l last
-l 
last
$ ./t.sh -o output -l last
-l 
last
$ ./t.sh  -l last
-l 
last
EoF_test

-3
mitsos@redhat24$ my_script "a=1;b=mitsos;c=karamitsos"
#!/bin/sh
eval "$1"

Sie haben gerade Befehlszeilenparameter in den Gültigkeitsbereich des Skripts eingefügt !!


3
Dies funktioniert nicht mit der vom OP angegebenen Syntax. sie wollen-a 1 -b mitsos -c karamitsos
Michael Mrozek
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.