简体   繁体   English

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

[英]Passing arguments to bash -c with spaces

I have the command line arguments to a program stored in a bash array and one of the arguments can have spaces in it. 我在bash数组中存储了程序的命令行参数,其中一个参数可以在其中包含空格。 X=(AB "CD" E)

I have another constraint that I need to execute my program through a bash -c statement. 我还有另一个约束,需要通过bash -c语句执行程序。 (Technically it is a ... | xargs bash -c "./a.out ..." statement) (从技术上讲,它是... | xargs bash -c "./a.out ..."语句)

When I do this, I end up mangling the spaces in my command. 当我这样做时,我最终在命令中修改了空格。 How can I do this correctly? 如何正确执行此操作?

I wrote a quick c++ program to output command line arguments to represent my program 我写了一个快速的c ++程序来输出命令行参数来表示我的程序

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

I am looking to get the output from ./a.out "${X[@]}" 我希望从./a.out "${X[@]}"获取输出

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

but when I test this bash -c "./a.out ${X[@]}" I just get just get 但是当我测试这个bash -c "./a.out ${X[@]}"我得到的只是

"A"

and when I test this bash -c "./a.out ${X[*]}" it mangles the spaces and I get 当我测试这个bash -c "./a.out ${X[*]}"它弄乱了空格,我得到了

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

What can Ido? 我能做什么?

The Right Way(s) 正确的方法

Passing data out-of-band from code 从代码带外传递数据

Since you're using xargs , consider passing data through the argument list of the shell itself, not inside the script passed with -c : 由于您使用的是xargs ,请考虑通过外壳本身的参数列表传递数据,而不是通过-c传递的脚本内部传递数据:

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

Because the "$@" is itself in single quotes, it isn't expanded by the parent shell, but instead by the child shell that's passed other arguments by xargs. 因为"$@"本身用单引号引起来,所以它不会由父外壳扩展,而是由xargs传递其他参数的子外壳扩展。 (The _ is there to act as a placeholder for $0 ). _充当$0的占位符)。

This is actually a best practice even in cases where the number of arguments is fixed: It the potential for shell injection attacks via malicious data substituted directly into your script text. 即使在参数数目固定的情况下,这实际上也是最佳实践:它有可能通过直接替换为脚本文本的恶意数据进行Shell注入攻击。


Using printf %q to create eval -safe content 使用printf %q创建eval内容

ksh, bash, and zsh include a %q operator to printf which quotes content in an eval -safe manner: ksh,bash和zsh包括一个%q运算符,用于printf ,以eval方式引用内容:

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

Why The Wrong Ways Didn't Work 为什么错误的方式行不通

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

When "${foo[@]}" is expanded inside a string, the result is an array with contents before that expansion prepended to the first element, additional elements prior to the last one emitted standalone, and any contents of the string after the last one appended to the last element. 字符串扩展"${foo[@]}" ,结果是一个数组,其内容之前的扩展内容将附加在第一个元素之前,最后一个元素之前的其他元素将独立发出,而字符串后面的所有内容最后一个附加到最后一个元素。 Thus bash -c "./a.out begin${X[@]}end" expands to: 因此bash -c "./a.out begin${X[@]}end"扩展为:

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

...thus, B , CD and E are all passed to your shell, but outside of the -c argument; ...因此, BCDE都传递给您的shell,但是在-c参数之外; they can be accessed with "$@" , or looking at $1 , $2 , etc. 可以使用"$@"或查看$1$2等来访问它们。


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

By contrast, with "${foo[*]} , the result is the first character of IFS (by default, a simple space) being substituted between each array element. Thus: 相比之下,使用"${foo[*]} ”的结果是在每个数组元素之间替换了IFS的第一个字符(默认情况下是一个简单的空格)。

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

...becomes... ...成为...

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

...such that the space literal between C and D becomes indistinguishable from the literal spaces placed between other characters by the expansion process. ...使得CD之间的空格文字与通过扩展过程放置在其他字符之间的文字空格无法区分。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM