将命名参数传递给Shell脚本


114

有没有简单的方法可以将命名参数传递(接收)到Shell脚本?

例如,

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 -它有助于命名参数和不输入验证,太
垮掉

Answers:


34

可能最接近的语法是:

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

7
与此相关的是,如果-k调用外壳程序中设置了该选项,则my_script p_out='/some/path' arg_1='5'效果相同。(将赋值形式的所有参数添加到环境中,而不仅仅是命令前的那些赋值。)
chepner 2014年

13
我曾经喜欢这种语法,但是它有一个很大的警告:在执行命令/函数之后,那些变量仍将在当前作用域中定义!例如:x=42 echo $x; echo $x这意味着在下一次执行时my_script,如果p_out省略,它将保持上次通过的值!('/some/path'
卢卡斯·西蒙

@LucasCimon您能否unset在第一次执行后将其重置,而在下一次执行之前将其重置?
Nikos Alexandris

2
@LucasCimon这是不正确的。x=42 echo $x如果$x之前没有定义,则不会输出任何内容。
Hauke Laging,

您说得对@HaukeLaging,感谢您纠正此问题
Lucas Cimon

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

有一个有用的Small getopts教程,或者您可以help getopts在shell提示符下键入。


25
这应该是公认的答案
Kaushik Ghose

3
我知道这有点老了,但是为什么参数只用1个字母呢?
凯文

1
我实现了这一点(但使用id)。当我运行它时,my_script -i asd -d asd我得到一个空字符串作为d参数。运行它时my_script -d asd -i asd,两个参数都为空字符串。
Milkncookiez

3
@Milkncookiez-我有一个类似的问题-我在最后一个参数之后没有加':'(我的情况是'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)
可以满足

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

准备在脚本中使用STEPSREPOSITORY_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类似GNU 的语法getopt(3)


您知道zparseopts为什么仅对参数使用一个破折号而在参数中[]却是两个破折号吗?没有道理!
Timo

@Timo,看到info zsh zparseopts的细节
斯特凡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

而且您想接受可变数量的选项/值对,

也不想要一棵巨大的“如果...那么..否则..fi”树,

然后,在检查参数计数是否为非零甚至偶数之后,

使用这四个eval语句作为主体编写while循环,然后使用在每次循环中确定的两个值编写case语句。

此处演示了脚本的棘手部分:

#!/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
Michael Mrozek
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.