Ü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.