我正在编写一个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'"
的东西来转义引号,但我不能保证用户会这样做。
8条答案
按热度按时间ccgok5k51#
引号在参数传递到脚本之前就被删除了,所以现在要保留它们已经太晚了。您可以做的是在将参数传递给内部命令时保留它们的效果,并重新构造参数的等效引号/转义版本以进行打印。
为了将参数传递给内部命令
"$@"
(带双引号),$@保留了原始的单词分隔符,这意味着内部命令接收的参数列表与脚本接收的参数列表完全相同。对于打印,可以在bash的printf命令中使用%q格式来重新构造引号。请注意,这并不总是重构原始的引号,而是构造一个 * 等效 * 的引号/转义字符串。例如,如果你传递参数
'uptime ; uname -a'
,它可能会打印uptime\ \;\ uname\ -a
或"uptime ; uname -a"
或任何其他等效的值(类似的例子见@William Pursell的答案)。下面是一个使用这些的示例:
字符串
如果您有bash 4.4或更高版本,您可以在参数展开上使用
@Q
修饰符来添加引号。这倾向于使用单引号(而不是printf %q
对转义的偏好)。您可以将其与$*
结合使用,以获得合理的结果:型
请注意,
$*
将所有参数混合到一个字符串中,它们之间有空格,这通常是没有用的,但在这种情况下,每个参数都被单独引用,因此结果实际上是您(可能)想要的。(好吧,除非你改变了IFS
,在这种情况下,参数之间的“空格”将是$IFS
的第一个字符,这可能不是你想要的。i1icjdpr2#
使用${@@Q}可获得简单的解决方案。为了测试,将下面的行放在脚本bigQ中。
字符串
llew8vvj3#
如果用户调用您的命令为:
字符串
给脚本的第一个参数是不带引号的字符串
foo
。你的脚本没有办法区分它和任何其他可以获取foo
作为参数的方法(例如./script $(echo foo)
或./script foo
或./script "foo"
或./script \f\o""''""o
)。46scxncf4#
如果要打印尽可能接近用户可能输入内容的参数列表:
字符串
它并不完美。像
''\''"'
这样的论证比合理的论证更难适应。ryhaxcpt5#
正如其他人已经提到的,当您访问脚本中的参数时,要知道调用时引用了哪些参数已经为时已晚。但是,您可以对包含空格或其他特殊字符的参数重新加引号,这些字符需要加引号才能作为参数传递。
下面是一个基于Python的
shlex.quote(s)
的Bash实现,它可以做到这一点:字符串
您的示例稍微更改为显示空参数:
型
p8h8hvxi6#
在我的例子中,我尝试调用bash,如
script --argument="--arg-inner=1 --arg-inner2"
。不幸的是,任何解决方案上不帮助我的情况。最终解决方案为
字符串
在MacOS的情况下,结果是
--argument=--arg-inner=1\ --arg-inner2
,这在逻辑上是相同的。qeeaahzv7#
我有一个非常简单的解决方案,也适用于
sh
shell:script1.sh
字符串
当我调用
script1.sh
时:./script1.sh sh -c "serve -l 9527 -s dist"
个产出将是:
型
如您所见,第一行回显保留引号的字符串;第二行通过使用
eval
直接执行sh -c "serve -l 9527 -s dist"
。请注意,您可以将任何想要评估的命令作为script1.sh
的参数传递。ubby3x7f8#
只需使用引号和nul字符分隔每个参数:
字符串
如Charles Duffy所述。