bash 如何在bash中分隔传递给eval的多个命令

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/17821277/
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-18 06:00:12  来源:igfitidea点击:

How to separate multiple commands passed to eval in bash

bashshelleval

提问by Yihui Xie

I'm trying to evaluate multiple lines of shell commands using eval, but when I try to resolve variables with eval separated by a newline \nthe variables are not resolved.

我正在尝试使用 评估多行 shell 命令eval,但是当我尝试使用由换行符分隔\n的eval 解析变量时,变量未解析。

x='echo a'
y='echo b'
z="$x\n$y"
eval $x
eval $y
eval $z

Which outputs:

哪些输出:

a
b
anecho b

The last command gives anecho b, and apparently \nwas treated as nthere. So is there a way to evaluate multiple lines of commands (say, separated by \n)?

最后一个命令给出anecho b,显然\n被视为在n那里。那么有没有办法评估多行命令(例如,用 分隔\n)?

采纳答案by Gordon Davisson

\nis not a newline; it's an escape sequence that in some situationswill be translated into a newline, but you haven't used it in one of those situations. The variable $zdoesn't wind up containing a newline, just backslash followed by "n". As a result, this is what's actually being executed:

\n不是换行符;这是一个转义序列,在某些情况下会被转换为换行符,但您没有在其中一种情况下使用它。该变量最终$z不包含换行符,只是反斜杠后跟“n”。结果,这是实际执行的内容:

$ echo a\necho b
anecho b

You can either use a semicolon instead (which requires no translation), or use \nin a context where it willbe translated into a newline:

您可以使用分号代替(不需要翻译),也可以\n被翻译为换行符的上下文中使用:

$ newline=$'\n'
$ x='echo a'
$ y='echo b'
$ z="$x$newline$y"
$ eval "$z"
a
b

Note the double-quotes around "$z"-- they're actually critical here. Without them, bash will word-split the value of $z, turning all whitespace (spaces, tabs, newlines) into word breaks. If that happens, evalwill receive the words "echo" "a" "echo" b", effectively turning the newline into a space:

注意周围的双引号"$z"——它们在这里实际上很重要。没有它们,bash 将对 的值进行分词$z,将所有空格(空格、制表符、换行符)转换为分词符。如果发生这种情况,eval将收到单词 "echo" "a" "echo" b",有效地将换行符转换为空格:

$ eval $z
a echo b

This is yet another in the long list of cases where it's important to double-quote variable references.

这是双引号变量引用很重要的一长串案例中的另一个。

回答by Eric Leschinski

You are passing the newline into eval. So it's like you are on the console typing this:

您正在将换行符传递给 eval。所以就像你在控制台上输入:

el@voyager$ echo a\necho b
anecho b

So the first echois understood correctly, and it thinks you want quotes around the rest. The backslash seems to be ignored. Perhaps you meant something like this:

所以第一个echo被正确理解,它认为你想要引用其余的。反斜杠似乎被忽略了。也许你的意思是这样的:

el@voyager$ echo -e 'a\n'; echo b
a

b

Option 1:

选项1:

delimit statements passed into eval with a semicolon like this:

使用分号传递给 eval 的分隔语句如下:

x='echo a'
y='echo b'
z="$x;$y"
eval $x
eval $y
eval $z

prints:

印刷:

a
b
a
b

Option 2:

选项 2:

Put the newline in the place where it will be interpreted by the echo, like this:

将换行符放在 echo 将解释的位置,如下所示:

x='echo -e "a\n"'
y='echo b'
z="$x;$y"
eval $x
eval $y
eval $z

prints:

印刷:

a

b
a

b

Now the newline is preserved and interpreted by the echo, not the eval.

现在换行符由回声保留和解释,而不是由评估。

回答by jlliagre

Not necessarily the optimal way as it will fail if the xand yvariables contain sequences processed by printf like %sand similar but anyway, here is a method to do it while keeping \nas a separator:

不一定是最佳方式,因为如果xy变量包含由 printf like%s和 similar处理的序列,它将失败,但无论如何,这是一种在保留\n作为分隔符的同时执行此操作的方法:

x='echo a'
y='echo b'
z="$x\n$y"
eval $x
eval $y
export IFS=" "
eval $(printf "$z")

prints:

印刷:

a
b
a
b

回答by d0c_s4vage

A slightly different approach:

一种稍微不同的方法:

read -r -d '' script <<'EOF'
echo a
echo b
EOF

eval "$script"

outputs

输出

a
b

Explanation

解释

  • read -r -d '' script
    • -r- do not allow backslashes to escape any characters
    • -d ''- continue until the first character of DELIM is read, rather than newline (makes it read until EOF)
    • script- the name of the variable to save the result in
  • <<'EOF'- use a heredoc WITHOUT variable expansion (the single quotes around the EOFstops the variable expansion)
  • read -r -d '' script
    • -r- 不允许反斜杠转义任何字符
    • -d ''- 继续直到读到 DELIM 的第一个字符,而不是换行符(让它读到 EOF)
    • script- 保存结果的变量名
  • <<'EOF'- 使用没有变量扩展的heredoc(围绕EOF停止变量扩展的单引号)

Alternative

选择

This could also be done using $(cat <<'EOF'...EOF), but this way does not needlessly use cat and does not use a subshell.

这也可以使用 来完成$(cat <<'EOF'...EOF),但这种方式不会不必要地使用 cat 并且不使用子shell。

Example with useless cat:

无用猫的示例:

script=$(cat <<'EOF'
echo a
echo b
EOF
)

eval "$script"

回答by Manish Jain

On my FreeBSD box, I was trying do something in a Bourne script which at first seemed fairly trivial - but clouded my mind for a few moments. Since this page is what I referred to trying to fix my problem, I will explain what I needed to do and how I got it done :

在我的 FreeBSD 机器上,我试图在 Bourne 脚本中做一些事情,这起初看起来相当微不足道 - 但有一段时间让我的头脑蒙上了一层阴影。由于这个页面是我提到的试图解决我的问题的页面,我将解释我需要做什么以及我是如何完成的:

a=A

b=B

eval ${a}_${b}="something"

No problems so far. I get a new variable A_B that stores "something"

到目前为止没有问题。我得到了一个存储“东西”的新变量 A_B

But if I spread the assignment over 2 lines as under :

但是,如果我将作业分成 2 行,如下所示:

eval ${a}_${b}="some

thing"

The shell barks back at me that it could find no command called 'thing'. It is important to understand that eval tries to evaluate RHS as a command. To get eval to evaluate RHS as a string, you have to double-double quote RHS :

外壳对我咆哮说它找不到名为“事物”的命令。重要的是要了解 eval 尝试将 RHS 评估为命令。要让 eval 将 RHS 评估为字符串,您必须双双引号 RHS :

eval ${a}_${b}="\"some

thing\""

Hope this helps someone. Manish Jain

希望这可以帮助某人。马尼什耆那教