Passando argomenti denominati a script di shell


114

Esiste un modo semplice per passare (ricevere) parametri con nome a uno script di shell?

Per esempio,

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

E dentro my_script.shli ricevi come:

# 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"

È possibile in Bash o Zsh?


2
dai un'occhiata a docopt - aiuta con i parametri nominati e inserisce anche la convalida
Batti

Risposte:


34

La sintassi probabilmente più vicina a questa è:

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

7
A questo proposito, se l' -kopzione è impostata nella shell chiamante , my_script p_out='/some/path' arg_1='5'ha lo stesso effetto. (Tutti gli argomenti sotto forma di un compito vengono aggiunti all'ambiente, non solo quelli che precedono il comando.)
chepner

13
Adoravo questa sintassi, ma ha un grande avvertimento: dopo l'esecuzione del comando / funzione, quelle variabili saranno ancora definite nell'ambito attuale! Ad esempio: il x=42 echo $x; echo $xche significa che nella prossima esecuzione di my_script, se p_outomesso, si atterrà al valore passato l'ultima volta !! ( '/some/path')
Lucas Cimon

@LucasCimon Non riesci a riprodurli unsetdopo la prima esecuzione, a ripristinarli prima dell'esecuzione successiva?
Nikos Alexandris,

2
@LucasCimon Non è corretto. x=42 echo $xnon emette nemmeno nulla se $xnon è stato definito prima.
Hauke ​​Laging,

Hai ragione @HaukeLaging, grazie per averlo corretto
Lucas Cimon,

148

Se non ti dispiace essere limitato ai nomi di argomenti a lettera singola my_script -p '/some/path' -a5, ad esempio , in bash potresti usare il built-in getopts, ad es

#!/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"

Quindi puoi farlo

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

Esiste un utile tutorial su Small getopts oppure puoi digitare help getoptsal prompt della shell.


25
Questa dovrebbe essere la risposta accettata
Kaushik Ghose,

3
So che è un po 'vecchio, ma perché solo 1 lettera per gli argomenti?
Kevin,

1
Ho implementato questo (ma con ie d). Quando lo eseguo my_script -i asd -d asdottengo una stringa vuota per l' dargomento. Quando lo eseguo my_script -d asd -i asdottengo una stringa vuota per entrambi gli argomenti.
Milkncookiez,

3
@Milkncookiez - Ho avuto un problema simile - Non ho incluso un ':' dopo l'ultimo argomento (una 'w' nel mio caso). Una volta ho aggiunto ":" ha iniziato a funzionare come previsto
Derek

37

L'ho rubato da drupal.org , ma potresti fare qualcosa del genere:

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

L'unica avvertenza è che devi usare la sintassi my_script --p_out=/some/path --arg_1=5.


7
L'avvertenza non è necessaria. :) Puoi avere le condizioni come segue:-c|--condition)
Milkncookiez,

28

Uso questo script e funziona come un incantesimo:

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"

uso

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

Risultato della console:

STEPS = ABC
REPOSITORY_NAME = stackexchange

STEPS e REPOSITORY_NAME sono pronti per l'uso nello script.

Non importa in quale ordine siano gli argomenti.


4
Questo è pulito e dovrebbe essere la risposta accettata.
miguelmorin,

15

Con zsh, useresti 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"

Ma avresti chiamato la sceneggiatura con myscript --p_out foo.

Nota che zparseoptsnon supporta abbreviare le opzioni lunghe o la --p_out=foosintassi come GNU getopt(3).


Sai perché zparseopts usa solo un trattino per gli argomenti mentre in []esso sono 2 trattini? Non ha senso!
Timo

@Timo, vedi info zsh zparseoptsper i dettagli
Stéphane Chazelas,

9

Ho appena creato questo script

while [ $# -gt 0 ]; do

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

  shift
done

passalo come my_script --p_out /some/path --arg_1 5e poi nello script puoi usare $arg_1e $p_out.


Mi piace questa soluzione in KSH88 che ho dovuto v=``echo ${1} | awk '{print substr($1,3)}'`` typeset $v="$2"(rimuovere un backtick per lato)
hol

-2

Se una funzione o un'applicazione ha più di zero argomenti, ha sempre un ultimo argomento.

Se vuoi leggere l'opzione flag e le coppie di valori, come in: $ ./t.sh -o output -i input -l last

E vuoi accettare un numero variabile di coppie opzione / valore,

E non voglio un grande albero "se .. allora .. altro .. fi",

Quindi, dopo aver verificato il conteggio di un argomento diverso da zero e pari,

Scrivi un ciclo while con queste quattro istruzioni eval come corpo, seguito da un'istruzione case usando i due valori determinati in ciascun passaggio attraverso il ciclo.

La parte difficile dello scripting è dimostrata qui:

#!/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"

hai appena inserito i parametri della riga di comando all'interno dell'ambito dello script !!


3
Questo non funziona con la sintassi specificata dall'OP; vogliono-a 1 -b mitsos -c karamitsos
Michael Mrozek
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.