我有一个存储在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可以做什么?
答案 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"
...因此,B
,C D
和E
都传递给您的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"
...使得C
和D
之间的空格文字与扩展过程中放置在其他字符之间的文字空间无法区分。