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
How to separate multiple commands passed to eval in bash
提问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 \n
the 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 \n
was treated as n
there. So is there a way to evaluate multiple lines of commands (say, separated by \n
)?
最后一个命令给出anecho b
,显然\n
被视为在n
那里。那么有没有办法评估多行命令(例如,用 分隔\n
)?
采纳答案by Gordon Davisson
\n
is 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 $z
doesn'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 \n
in 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, eval
will 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 echo
is 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 x
and y
variables contain sequences processed by printf like %s
and similar but anyway, here is a method to do it while keeping \n
as a separator:
不一定是最佳方式,因为如果x
和y
变量包含由 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 theEOF
stops 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
希望这可以帮助某人。马尼什耆那教