使用空格向bash-c传递参数
我有一个存储在bash数组中的程序的命令行参数,其中一个参数可以包含空格<代码>X=(A B“C D”E) 我还有另一个约束,我需要通过使用空格向bash-c传递参数,bash,shell,spaces,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
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;
}
但是当我测试这个bash-c“/a.out${X[@]}”
时,我得到了
"A"
当我测试这个bash-c“/a.out${X[*]}”
"A"
"B"
"C"
"D"
"E"
我能做什么?正确的方法
从代码向带外传递数据
由于您使用<代码> xARGs<代码>,请考虑通过shell本身的参数列表传递数据,而不是在用<代码> -c>代码>的脚本中传递数据:
xargs bash -c './a.out "$@"' _
因为“$@”
本身是单引号,所以它不是由父shell展开的,而是由xargs传递其他参数的子shell展开的。(这里的
用作$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[@]}”
在字符串中展开时,结果是一个数组,其中该展开之前的内容在第一个元素前面,最后一个元素之前的其他元素独立发出,最后一个元素之后的字符串的任何内容附加到最后一个元素。因此,bash-c“/a.out begin${X[@]}end”
扩展为:
bash -c "./a.out beginA" "B" "C D" "Eend"
…因此,B
、cd
和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
之间的文字空间就无法与扩展过程中放置在其他字符之间的文字空间区分开来。正确的方式
从代码向带外传递数据
由于您使用<代码> xARGs<代码>,请考虑通过shell本身的参数列表传递数据,而不是在用<代码> -c>代码>的脚本中传递数据:
xargs bash -c './a.out "$@"' _
因为“$@”
本身是单引号,所以它不是由父shell展开的,而是由通过xargs传递其他参数的子shell展开的。(\uuu
在那里充当$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[@]}”
在字符串中展开时,结果是一个数组,其中该展开之前的内容在第一个元素前面,最后一个元素之前的其他元素独立发出,最后一个元素之后的字符串的任何内容追加到最后一个元素。因此bash-c./a.out begin${X[@]}end“
扩展为:
bash -c "./a.out beginA" "B" "C D" "Eend"
…因此,B
、cd
和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
之间的文字空间就无法与扩展过程中放置在其他字符之间的文字空间区分开来。顺便说一句,我认为这是BashFAQ#50的一个特例;顺便说一句,你想让我的答案说明为什么你的尝试会以这种方式进行,而不是仅以这种方式进行讨论正确的事情?(谈到正确的事情,以文字形式显示参数的更简单的测试程序是一个bash脚本,在shebang之后有一行:printf'%q\n'$@
;您可以使用'%s“\n'
以获得与现有C程序等效的行为,但输出格式不明确,因为参数可以同时包含引号和换行符)。谢谢。我来看看这个。我在玩IFS游戏,试图让空间不混在一起,但那感觉不对。我的同事刚刚说了“去掉空间”,但那感觉像是失去了学习的机会。如果目标是学习,我会扩展答案,详细介绍你尝试过的东西的行为。顺便说一句,我认为这是BashFAQ 50的一个特例;顺便说一句,你想让我的答案说明为什么你的尝试是这样的,而不是只讨论正确的事情吗?(说到正确的事情,一个更容易用文字形式显示参数的测试程序是一个bash脚本,在shebang之后有一行:printf'%q\n'$@'
;你可以