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

时间:2021-04-07 20:26:04

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 decho that printed each positional parameter on it's own line:

我将用一个例子来解释我的问题。让我们说我有一个函数decho,在它自己的行上打印每个位置参数:

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

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

好的,如果我去de b 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 $args in decho $args be word-split the way I expected?

但这似乎有点笨重。是否有一种更好的方法可以按照我预期的方式对$ args中的$ args进行扩展?

5 个解决方案

#1


4  

You can use:

您可以使用:

eval decho $args

#2


2  

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

#3


0  

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 :-)

直接记忆,不保证:-)

#4


0  

hmmm.. eval decho $args works 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.

我可以使用“$ {array [@]}”(类似于“$ @”)对bash数组做一些事情,但是我必须编写代码来加载数组,这将是一个痛苦。

#5


0  

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的变量。对于命令,然后您可以将其更改为将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 metachars不会造成破坏。

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 "$1"
arg1 ; man arg4

#1


4  

You can use:

您可以使用:

eval decho $args

#2


2  

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

#3


0  

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 :-)

直接记忆,不保证:-)

#4


0  

hmmm.. eval decho $args works 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.

我可以使用“$ {array [@]}”(类似于“$ @”)对bash数组做一些事情,但是我必须编写代码来加载数组,这将是一个痛苦。

#5


0  

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的变量。对于命令,然后您可以将其更改为将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 metachars不会造成破坏。

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 "$1"
arg1 ; man arg4