我希望我的剧本被称为:
./script -f "-a -b "foo bar"" baz其中-a -b "foo bar"是命令行参数,要传递给由我的脚本在内部执行的命令(例如grep)。
这里的问题当然与引用有关:天真的方法(将命令行参数扩展到script)将foo和bar视为单独的参数,这当然是不可取的。
做这件事最好的方法是什么?
发布于 2015-12-19 06:06:56
没有真正伟大的方式来实现这一点,只有解决办法。几乎所有常见的解决方案都涉及将单个论点作为单独的论点传递,因为另一种方法--将一系列的参数作为一个单一的参数传递--使您每次想要传递一个甚至稍微复杂的论点时,都会跳过一圈火(结果会发现,这是很常见的;您的例子只是即将陷入的元引语的开始。)有关更多见解,请参见这个Bash FAQ条目 )。
最常见的解决方案可能是将要传递的参数放在参数列表的末尾。这意味着您需要知道实际用于脚本的参数的结尾,这或多或少意味着有固定数量的位置参数。通常,固定的数字是1。这个策略的一个例子是任何脚本解释器(bash本身、python等等)。其中只有一个位置参数,脚本的名称。这将使您的调用:
./script baz -a -b "foo bar"这不总是方便的。例如,find命令有一个-exec选项,后面跟着以下参数中的实际命令。要做到这一点,您必须知道要通过end传递的单词在哪里;find通过使用一个特定的分隔符参数来解决这个问题:一个分号。(这是一个武断的选择,但作为脚本参数非常罕见,因此它通常是可行的。)在这种情况下,调用如下所示:
./script -f -a -b "foo bar" \; baz显然,需要引用;,因为否则它将终止命令,但这并不是一个复杂的引用问题。
它可以通过允许用户显式指定分隔词来扩展:
./script --arguments=--end -a -b "foo bar" --end baz下面是find-like建议的一些示例代码:
# Use an array to accumulate the arguments to be passed through
declare -a passthrough=()
while getopts f:xyz opt; do
case "$opt" in
f)
passthrough+=("$OPTARG")
while [[ ${!OPTIND} != ';' ]]; do
if ((OPTIND > $#)); then
echo "Unterminated -f argument" >>/dev/stderr
exit 1
fi
passthrough+=("${!OPTIND}")
((++OPTIND))
done
((++OPTIND))
;;
# Handle other options
esac
done
# Handle positional arguments
# Use the passthrough arguments
grep "${passthrough[@]}" # Other grep arguments发布于 2017-09-30 11:59:17
我发现了一个较短的方法,可以将脚本参数作为参数传递给只有限制的命令:应该对命令进行计算。
在你的问题中,下面的script会做你想做的事情
#!/bin/bash
# Do whatever you want ...
# Just claim that 2nd quoted argument of script should be passed as
# a set of parameters of grep
eval grep $2然后,您可以使用空间(包括要传递给script的参数)调用这个grep。
./script -f "-a -b \"foo bar\"" baz或
./script -f '-a -b "foo bar"' baz瞧!将使用正确的参数调用grep。
grep -a -b "foo bar"例如,调用
./script -f '-i "system message" /etc/passwd' baz然后得到正确的输出
dbus:x:81:81:System message bus:/:/sbin/nologinhttps://stackoverflow.com/questions/34367098
复制相似问题