如何传递存储在单个variables中的引号的命令行参数?

我想从shell脚本调用外部应用程序,但是这个shell脚本从一个variables中获取参数(来自其他脚本)。 一切都还好,直到我不必为单个参数使用双引号,而是用空格隔开单词。

这里是我的问题的简化例子(sh_param只是打印所有传递的参数):

#!/bin/sh pass() { echo "Result with \$@" ./sh_param $@ echo "Result with \"\$@\"" ./sh_param "$@" echo "Result with \$*" ./sh_param $* echo "Result with \"\$*\"" ./sh_param "$*" } pass '"single param" separate params' 

和结果(sh_param只是打印所有传递的参数):

 Result with $@ Param: "single Param: param" Param: separate Param: params Result with "$@" Param: "single param" separate params Result with $* Param: "single Param: param" Param: separate Param: params Result with "$*" Param: "single param" separate params 

而且我要:

 Param: single param Param: separate Param: params 

Solutions Collecting From Web of "如何传递存储在单个variables中的引号的命令行参数?"

脚本

 pass() { echo 'Result with "$@"' sh_param "$@" } sh_param() { for i in "$@" do echo Param: $i done } pass "single param" separate param 

结果

 Result with "$@" Param: single param Param: separate Param: param 

如果你被一个变量卡住,你将不得不使用eval

 $ show() { i=0; for param; do ((i++)); echo "$i>$param"; done; } $ show '"single param" separate params' 1>"single param" separate params $ eval show '"single param" separate params' 1>single param 2>separate 3>params 

请注意,双引号是由外壳吃掉的。

避免把整个事情作为一个单一的论点来传递(就像你用squotes一样)。 使shell脚本很难保持传递参数的数量,而不需要通过将它们变成字符串并再次扩展它们来使其更难。

如果您确实需要,还是有一些最佳实践需要遵循。 我不得不写一个脚本作为su / sudo包装器:su采取一个单一的论据,它传递给sh评估; sudo将任意数量的未经修改的参数传递给execv(e)。

你必须非常小心才能使它变得可移植,而不会在晦涩的shell中遇到问题。 整个脚本对于发布并不是很有用,但是一般的要点是编写一些转义函数,并且非常执行引用来建立一个防弹的,不可读的,小心谨慎的字符串,这个字符串是安全的,可以传递给eval

 bash_escape() { # backtick indirection strictly necessary here: we use it to strip the # trailing newline from sed's output, which Solaris/BSD sed *always* output # (unlike GNU sed, which outputs "test": printf %s test | sed -es/dummy//) out=`echo "$1" | sed -es/\\'/\\''\\\\'\\'\\'/g` printf \'%s\' "$out" } append_bash_escape() { printf "%s " "$1" bash_escape "$2" } sed_escape() { out=`echo "$1" | sed -e 's/[\\/&]/\\\\&/g'` printf %s "$out" } 

这些有用的函数可以让你做这样的事情来构建命令字符串:

 COMMAND= while [ $# -gt 0 ] ; do COMMAND=`append_bash_escape "$COMMAND" "$1"` ; shift done 

然后可以操作命令字符串,例如对其运行bash_escape并使用sed_escape替换字符串"su - root -c SUB_HERE" ,或者直接将其替换为像"sudo -- SUB_HERE"这样的字符串。 然后,您可以安全地eval一些东西,而不用担心元字符,参数分裂,未转化的小块等等。

是偏执狂,单元测试你的脚本,你可以想到的每一个讨厌的输入,以确保你的论点分裂和保存是正确的!

这可能会起作用,尽管如果不知道sh_param如何处理它的参数很难说sh_param

 #!/bin/sh pass() { echo "Result with \"\$@\"" ./sh_param "$@" } pass "single param" separate params 

回答我自己的问题。 非常感谢pzanoni。 xargs似乎正确地解析了任何你正在投向它的东西:-)“$ @”,“$ ”,$ @和$可以很好地处理它。 所以我现在的代码如下所示:

 #!/bin/sh pass() { echo $* | xargs ./sh_param } pass '"single param" separate params' 

结果是我想要的:

 Param: single param Param: separate Param: params