Передача названих аргументів скриптам оболонки


114

Чи є простий спосіб передати (отримати) названі параметри до сценарію оболонки?

Наприклад,

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

А всередині my_script.shїх отримують як:

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

Це можливо в Bash чи Zsh?


2
подивіться на docopt - він допомагає з названими параметрами і також перевіряє вхід
Beat

Відповіді:


34

Ймовірно найближчий до цього синтаксис:

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

7
З цим пов'язано, якщо -kопція встановлена ​​в оболонці виклику , то my_script p_out='/some/path' arg_1='5'має той же ефект. (Усі аргументи у вигляді завдання додаються до середовища, а не лише ті завдання, що передують команді.)
Чепнер

13
Раніше я любив цей синтаксис, але він має BIG застереження: після виконання команди / функції ці змінні все ще будуть визначені в поточній області застосування! Напр .: x=42 echo $x; echo $xЩо означає, що при наступному виконанні my_script, якщо p_outвоно пропущено, воно буде дотримуватися значення, переданого в останній раз !! ( '/some/path')
Лукас Кімон

@LucasCimon Чи не можете ви unsetїх після першого виконання скинути до наступного виконання?
Нікос Олександріс

2
@LucasCimon Це невірно. x=42 echo $xнавіть не виводить нічого, якщо $xне було визначено раніше.
Hauke ​​Laging

Ви маєте рацію @HaukeLaging, дякую, що виправили це
Лукас Кімон,

147

Якщо ви не заперечуєте, щоб обмежитися однобуквенними іменами аргументів, тобто my_script -p '/some/path' -a5, в bash ви можете використовувати вбудовані getopts, наприклад

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

Тоді ви можете зробити

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

Існує корисний підручник з малим getopts, або ви можете ввести help getoptsпідказку оболонки.


25
Це має бути прийнята відповідь
Каушик Гесо

3
Я знаю, це трохи старе, але чому лише 1 лист для аргументів?
Кевін

1
Я реалізував це (але з iі d). Коли я запускаю його, my_script -i asd -d asdя отримую порожню рядок для dаргументу. Коли я запускаю його, my_script -d asd -i asdя отримую порожній рядок для обох аргументів.
Milkncookiez

3
@Milkncookiez - У мене була схожа проблема - я не включав ':' після останнього аргументу (a 'w' у моєму випадку). Після того, як я додав ':', він почав працювати, як очікувалося
Дерек

37

Я вкрав це з drupal.org , але ви могли зробити щось подібне:

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

Єдине застереження - це те, що ви повинні використовувати синтаксис my_script --p_out=/some/path --arg_1=5.


7
Застереження не потрібно. :) Ви можете мати такі умови:-c|--condition)
Milkncookiez

28

Я використовую цей сценарій і працює як шарм:

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"

Використання

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

Результат консолі:

STEPS = ABC
REPOSITORY_NAME = stackexchange

КРОКИ та REPOSITORY_NAME готові до використання в сценарії.

Не має значення, в якому порядку розміщені аргументи.


4
Це акуратно і має бути прийнятою відповіддю.
miguelmorin

15

З zsh, ви б використовували 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"

Але ви б назвали сценарій за допомогою myscript --p_out foo.

Зверніть увагу, що zparseoptsне підтримує скорочення довгих параметрів або --p_out=fooсинтаксис, як getopt(3)це робить GNU .


Чи знаєте ви, чому zparseopts використовує лише один тире для аргументів, тоді як у []ньому 2 тире? Не має сенсу!
Тимо

@Timo, дивіться info zsh zparseoptsдеталі
Stéphane Chazelas

9

Я щойно придумав цей сценарій

while [ $# -gt 0 ]; do

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

  shift
done

передайте його як, my_script --p_out /some/path --arg_1 5а потім у скрипті ви можете використовувати $arg_1і $p_out.


Мені подобається це рішення в KSH88, який мені довелося v=``echo ${1} | awk '{print substr($1,3)}'`` typeset $v="$2"(Видалити по одній зворотному боці в кожну сторону)
hol

-2

Якщо функція або програма містить більше нуля аргументів, у неї завжди є останній аргумент.

Якщо ви хочете прочитати прапор опцій та пари значень, як у: $ ./t.sh -o output -i input -l last

І ви хочете прийняти змінну кількість опцій / значень пар,

І не хочу величезного дерева "якщо .. тоді .. інше .. фі",

Потім, перевіривши наявність аргументу ненульового та парного рівня,

Напишіть цикл час з цими чотирма операторами eval як тіло, а потім випадок справи, використовуючи два значення, визначені при кожному проходженні через цикл.

Тут викладена хитра частина сценаріїв:

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

Ви щойно ввели параметри командного рядка в межах сценарію !!


3
Це не працює з вказаним синтаксисом OP; хочуть-a 1 -b mitsos -c karamitsos
Майкл Мрозек
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.