为 shell 脚本指定命令行参数,例如 name=value 对
Posted
技术标签:
【中文标题】为 shell 脚本指定命令行参数,例如 name=value 对【英文标题】:Specify command line arguments like name=value pairs for shell script 【发布时间】:2011-07-26 20:21:55 【问题描述】:是否可以将命令行参数作为名称值对传递给 shell 脚本,例如
myscript action=build module=core
然后在我的脚本中,获取变量
$action
并处理它?
我知道 $1....等可用于获取变量,但不会像对那样是名称值。即使是这样,使用脚本的开发人员也必须注意以相同的顺序声明变量。我不想那样。
【问题讨论】:
我想你的答案就在这里:***.com/questions/2642707/… 是的,与内置的 bashgetopts
不同,getopt
也适用于 tcsh。
我猜这样的东西只适用于 bash。抱歉我没有指定,我使用的是 tcsh。
【参考方案1】:
这对我有用:
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
STEPS 和 REPOSITORY_NAME 已准备好在脚本中使用。
参数的顺序无关紧要。
HTH
【讨论】:
谢谢。批处理脚本是否有 Windows 等效项? 理论上,您可以使用自己的命令在 Windows 中复制此脚本。如果你需要的话,这里有一些复杂的 windows bats 链接: - github.com/krichter722/squirrel-sql/blob/master/archive/… - github.com/apache/tomcat/tree/master/bin【参考方案2】:在 Bourne shell 中,有一个很少使用的选项“-k
”,它会自动将命令行上指定为 name=value
的任何值放入环境中。当然,Bourne/Korn/POSIX shell 系列(包括 bash)也对命令名称前的 name=value
项执行此操作:
name1=value1 name2=value2 command name3=value3 -x name4=value4 abc
在正常的 POSIX-shell 行为下,command
在环境中使用name1
和name2
调用,并带有四个参数。在 Bourne(以及 Korn 和 bash,但不是 POSIX)shell -k
选项下,在环境中使用 name1
、name2
、name3
和 name4
调用它,并且只有两个参数。 bash
手册页(如man bash
)没有提到-k
的等价物,但它的工作原理与Bourne 和Korn shell 一样。
我想我从来没有认真使用过它(-k
选项)。
无法从脚本 (command
) 中得知环境变量是专门为此命令指定的;它们只是该脚本环境中的环境变量。
这是我所知道的最接近您要求的方法。我认为 C shell 系列不存在任何等价物。我不知道有任何其他参数解析器可以在命令行上从 name=value
对中设置变量。
有一些相当重要的警告(对于简单的值相对容易做到,但很难处理包含 shell 元字符的值),您可以这样做:
case $1 in
(*=*) eval $1;;
esac
这不是 C shell 系列。 eval
有效地完成了 shell 分配。
arg=name1=value1
echo $name1
eval $arg
echo $name1
【讨论】:
我试图找到将环境变量传递给像name=value command
这样的命令的信息。但是我在man bash
中找不到任何解释。是否有任何手册页记录这一点?
我刚刚在man bash
中找到了它:任何简单命令或函数的环境都可以通过在参数分配前加上前缀来临时扩充,如上文参数中所述。这些赋值语句只影响该命令看到的环境。
Bash 手册的几个部分讨论了在命令名称之前设置环境。一个是Simple Command Expansion。另一个是Environment 部分,它通过The Set Built-in 提供指向-k
的指针。【参考方案3】:
env action=build module=core myscript
你说你正在使用 tcsh。对于基于 Bourne 的 shell,您可以删除“env”,尽管将它留在那里是无害的。请注意,这适用于运行命令的 shell,而不是用于实现 myscript
的 shell。
如果您特别希望 name=value 对跟随命令名称,则需要在 myscript
内做一些工作。
【讨论】:
【参考方案4】:这是一个很老的问题,但仍然有效
我还没有找到切饼干的解决方案。我结合了上面的答案。为了我的需要,我创建了这个解决方案;这甚至适用于参数值中的white space
。
另存为argparse.sh
#!/bin/bash
: $1?
'Usage:
$0 --<key1>="<val1a> <val1b>" [ --<key2>="<val2a> <val2b>" | --<key3>="<val3>" ]'
declare -A args
while [[ "$#" > "0" ]]; do
case "$1" in
(*=*)
_key="$1%%=*" && _key="$_key/--/" && _val="$1#*="
args[$_key]="$_val"
(>&2 echo -e "key:val => $_key:$_val")
;;
esac
shift
done
(>&2 echo -e "Total args: $#args[@]; Options: $args[@]")
## This additional can check for specific key
[[ -n "$args['path']+1" ]] && (>&2 echo -e "key: 'path' exists") || (>&2 echo -e "key: 'path' does NOT exists");
@Example:注意,脚本的参数可以有可选前缀--
./argparse.sh --x="blah"
./argparse.sh --x="blah" --yy="qwert bye"
./argparse.sh x="blah" yy="qwert bye"
此脚本的一些有趣用例:
./argparse.sh --path="$(ls -1)"
./argparse.sh --path="$(ls -d -1 "$PWD"/**)"
以上脚本创建为 gist,参考:argparse.sh
【讨论】:
【参考方案5】:延续乔纳森的回答,这对我来说效果很好:
#!/bin/bash
if [ "$#" -eq "0" ]; then
echo "Error! Usage: Remind me how this works again ..."
exit 1
fi
while [[ "$#" > "0" ]]
do
case $1 in
(*=*) eval $1;;
esac
shift
done
【讨论】:
以上是关于为 shell 脚本指定命令行参数,例如 name=value 对的主要内容,如果未能解决你的问题,请参考以下文章
Shell特殊变量:Shell $0, $#, $*, $@, $?, $$和命令行参数
Shell特殊变量:Shell $0, $#, $*, $@, $?, $$和命令行参数
Shell特殊变量 $0, $#, $*, $@, $?, $$和命令行参数