使用空格将参数传递给bash -c

时间:2015-12-14 16:05:52

标签: bash shell spaces

我有一个存储在bash数组中的程序的命令行参数,其中一个参数可以包含空格。 X=(A B "C D" E)

我有另一个约束,我需要通过bash -c语句执行我的程序。 (从技术上讲,它是... | xargs bash -c "./a.out ..."声明)

当我这样做时,我最终会破坏我命令中的空格。我怎么能正确地做到这一点?

我写了一个快速的c ++程序来输出命令行参数来表示我的程序

#include <iostream>
int main(int argc, char** argv)
{
    for (int i = 1; i < argc; ++i)
        std::cout << '"' << argv[i] << '"' << std::endl;
    return 0;
}

我希望得到./a.out "${X[@]}"

的输出
"A"
"B"
"C D"
"E"

但是当我测试这个bash -c "./a.out ${X[@]}"时,我只是得到了

"A"

当我测试这个bash -c "./a.out ${X[*]}"时,它会破坏空间并且我得到

"A"
"B"
"C"
"D"
"E"

Ido可以做什么?

1 个答案:

答案 0 :(得分:4)

正确的方式

从代码

带外传递数据

由于您正在使用xargs,请考虑通过shell本身的参数列表传递数据,而不是在使用-c传递的脚本中传递数据:

xargs bash -c './a.out "$@"' _

因为"$@"本身是单引号,所以它不是由父shell扩展的,而是由子shell通过xargs传递的其他参数。 (_可用作$0)的占位符。

这实际上是一种最佳实践,即使在参数数量固定的情况下:通过直接替换到脚本文本中的恶意数据进行shell注入攻击的可能性。

使用printf %q创建eval - 安全内容

ksh,bash和zsh包含一个%q运算符printf,以eval方式引用内容 - 安全方式:

printf -v out_str '%q ' "${X[@]}"
bash -c "./a.out $out_str"

为什么错误的方法不起作用

bash -c './a.out "${X[@]}"'

"${foo[@]}"扩展 in 一个字符串时,结果是一个数组,其内容在该扩展前添加到第一个元素,最后一个元素之前的其他元素单独发出,以及任何最后一个元素追加到最后一个元素后的字符串内容。因此bash -c "./a.out begin${X[@]}end"扩展为:

bash -c "./a.out beginA" "B" "C D" "Eend"

...因此,BC DE都传递给您的shell,但在-c参数之外;可以使用"$@"访问它们,也可以查看$1$2等。

bash -c './a.out ${X[*]}'

相比之下,使用"${foo[*]},结果是IFS的第一个字符(默认情况下,一个简单的空格)在每个数组元素之间被替换。因此:

bash -c "./a.out ${X[*]}"

... ...变为

bash -c "./a.out A B C D E"

...使得CD之间的空格文字与扩展过程中放置​​在其他字符之间的文字空间无法区分。