如何在将多个参数保持在一起的同时在 bash 中传递完整的参数列表?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/560987/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-17 20:41:32  来源:igfitidea点击:

How can I pass a complete argument list in bash while keeping mulitword arguments together?

linuxbash

提问by David Dean

I am having some issues with word-splitting in bash variable expansion. I want to be able to store an argument list in a variable and run it, but any quoted multiword arguments aren't evaluating how I expected them to.

我在 bash 变量扩展中遇到了一些分词问题。我希望能够将参数列表存储在一个变量中并运行它,但是任何引用的多字参数都不会评估我期望它们如何。

I'll explain my problem with an example. Lets say I had a function dechothat printed each positional parameter on it's own line:

我会用一个例子来解释我的问题。假设我有一个函数decho将每个位置参数打印在自己的行上:

#!/bin/bash -u
while [ $# -gt 0 ]; do
  echo 
  shift
done

Ok, if I go decho a b "c d"I get:

好的,如果我去,decho a b "c d"我会得到:

[~]$ decho a b "c d"
a
b
c d

Which is what I expect and want. But on the other hand if I get the arguments list from a variable I get this:

这是我期望和想要的。但另一方面,如果我从变量中获取参数列表,我会得到:

[~]$ args='a b "c d"'
[~]$ decho $args
a
b
"c
d"

Which is not what I want. I can go:

这不是我想要的。我可以去:

[~]$ echo decho $args | bash
a
b
c d

But that seems a little clunky. Is there a better way to make the expansion of $argsin decho $argsbe word-split the way I expected?

但这似乎有点笨拙。有没有更好的方法使$argsin的扩展按decho $args我预期的方式进行分词?

采纳答案by mouviciel

You can use:

您可以使用:

eval decho $args

回答by Paused until further notice.

You can move the eval inside the script:

您可以在脚本中移动 eval:

#!/bin/bash -u
eval set -- $*
for i; 
do 
  echo $i;
done

Now you can do:

现在你可以这样做:

$ args='a b "c d"'
$ decho $args
a
b
c d

but you'll have to quote the arguments if you pass them on the CL:

但是如果您在 CL 上传递参数,则必须引用它们:

$ decho 'a b "c d"'
a
b
c d

回答by crobc1

It is fundamentally flawed to attempt to pass an argument list stored in a variable, to a command.

试图将存储在变量中的参数列表传递给命令从根本上是有缺陷的。

Presumably, if you have code somewhere to create a variable containing the intended args. for a command, then you can change it to instead store the args into an array variable:

据推测,如果您在某处有代码来创建包含预期参数的变量。对于命令,则可以将其更改为将 args 存储到数组变量中:

decho_argv=(a b 'c d')  # <-- easy!

Then, rather than changing the command "decho" to accommodate the args taken from a plain variable (which will break its ability to handle normal args) you can do:

然后,与其更改命令“decho”以适应从普通变量中获取的 args(这将破坏其处理普通 args 的能力),您可以执行以下操作:

decho "${decho_argv[@]}"  # USE DOUBLE QUOTES!!!

However, if you are the situation where you are trying to take arbitrary input which is expected to be string fields corresponding to intended command positional arguments, and you want to pass those arguments to a command, then you should instead of using a variable, read the data into an array.

但是,如果您尝试接受任意输入,该输入预计是与预期命令位置参数对应的字符串字段,并且您想将这些参数传递给命令,那么您应该而不是使用变量,阅读将数据放入数组中。

Note that suggestions which offer the use of eval to set positional parameters with the contents of an ordinary variable are extremely dangerous.

请注意,建议使用 eval 来设置带有普通变量内容的位置参数是非常危险的。

Because, exposing the contents of a variable to the quote-removal and word-splitting on the command-line affords no way to protect against shell metachars in the string in the variable from causing havoc.

因为,将变量的内容暴露给命令行上的引号删除和分词无法防止变量中字符串中的 shell 元字符造成严重破坏。

E.g., imagine in the following example if the word "man" was replaced with the two words "rm" and "-rf" and the final arg word was "*":

例如,想象在下面的例子中,如果单词“man”被替换为两个单词“rm”和“-rf”并且最后的arg单词是“*”:

Do Not Do This:

不要这样做:

> args='arg1 ; man arg4'
> eval set -- $args
No manual entry for arg4
> eval set -- "$args"        # This is no better
No manual entry for arg4
> eval "set -- $args"        # Still hopeless
No manual entry for arg4

> eval "set -- '$args'"  # making it safe also makes it not work at all!
> echo ""
arg1 ; man arg4

回答by David Dean

hmmm.. eval decho $argsworks too:

嗯..eval decho $args也有效:

[~]$ eval decho $args
a
b
c d

And I may be able to do something with bash arrays using "${array[@]}"(which works like "$@"), but then I would have to write code to load the array, which would be a pain.

我也许可以使用 bash 数组做一些事情"${array[@]}"(它的工作原理类似于"$@"),但是我必须编写代码来加载数组,这会很痛苦。

回答by olli-MSFT

Have you tried:

你有没有尝试过:

for arg in "$@"
do
        echo "arg $i:$arg:"
        let "i+=1"
done

Should yield something like:

应该产生类似的东西:

arg 1: a
arg 2: c d

in your case.

在你的情况下。

Straight from memory, no guarantee :-)

直接来自记忆,不保证:-)