保留bash参数中的引号

我正在做一个bash脚本,将打印并传递复杂的参数到另一个外部程序。

./script -m root@hostname,root@hostname -o -q -- 'uptime ; uname -a' 

我如何打印原始参数:

 -m root@hostname,root@hostname -o -q -- 'uptime ; uname -a' 

使用$@$*删除uptime ; uname -a的单引号uptime ; uname -a uptime ; uname -a这可能会导致不良的结果。 我的脚本不需要parsing每个参数。 我只需要打印/logging参数string,并将它们传递给另一个程序,完全如何给出它们。

我知道我可以用"'uptime ; uname -a'"这样的东西来避免引号,但我不能保证用户会这样做。

Solutions Collecting From Web of "保留bash参数中的引号"

在参数传递给脚本之前,引号会被删除,所以保存它们为时已晚。 你可以做的是在将参数传递给内部命令的时候保持它们的效果,并且重建一个等同的引用/转义版本的打印参数。

为了将参数传递给内部命令"$@" – 使用双引号,$ @保留原来的单词分隔符,这意味着内部命令接收到与脚本完全相同的参数列表。

对于打印,您可以在bash的printf命令中使用%q格式来重构引用。 请注意,这不会总是重建原始的引用,但会构建一个等效的引用/转义字符串。 例如,如果你通过了'uptime ; uname -a' 'uptime ; uname -a'可能会打印uptime\ \;\ uname\ -a"uptime ; uname -a"或任何其他等价物(请参阅@William Pursell对类似示例的回答)。

这里有一个使用这些的例子:

 printf "Running command:" printf " %q" innercmd "$@" # note the space before %q -- this inserts spaces between arguments printf "\n" innercmd "$@" 

如果你想打印参数列表尽可能接近用户可能输入的内容:

 #!/bin/bash chars='[ !"#$&()*,;<>?\^`{|}]' for arg do if [[ $arg == *\'* ]] then arg=\""$arg"\" elif [[ $arg == *$chars* ]] then arg="'$arg'" fi allargs+=("$arg") # ${allargs[@]} is to be used only for printing done printf '%s\n' "${allargs[*]}" 

这并不完美。 像''\''"'这样的说法比正确的说法更难以适应。

如果用户以如下方式调用您的命令:

 ./script 'foo' 

给脚本的第一个参数是没有引号的字符串foo 。 你的脚本没有办法区分它和其他任何可以将foo作为参数的方法(例如./script $(echo foo)./script foo./script "foo" ./script \f\o""''""o )。