13

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

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

哪个输出:

a
b
anecho b

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

4

6 回答 6

13

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

$ echo a\necho b
anecho b

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

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

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

$ eval $z
a echo b

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

于 2013-07-24T14:34:32.943 回答
5

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

el@voyager$ echo a\necho b
anecho b

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

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

b

选项1:

用分号传递给 eval 的分隔语句,如下所示:

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

印刷:

a
b
a
b

选项 2:

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

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

印刷:

a

b
a

b

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

于 2013-07-23T21:24:14.177 回答
3

不一定是最佳方式,因为如果xandy变量包含由 printf 处理的类似和类似的序列,它将失败,但无论如何,这里有一种方法可以在保持分隔符的%s同时做到这一点:\n

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

印刷:

a
b
a
b
于 2013-07-23T21:33:45.653 回答
3

稍微不同的方法:

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

eval "$script"

输出

a
b

解释

  • read -r -d '' script
    • -r- 不允许反斜杠转义任何字符
    • -d ''- 继续直到读取 DELIM 的第一个字符,而不是换行符(使其读取到 EOF)
    • script- 保存结果的变量名
  • <<'EOF'- 使用没有变量扩展的heredoc(单引号EOF停止变量扩展)

选择

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

无用猫的例子:

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

eval "$script"
于 2019-08-27T04:37:05.663 回答
0

您是否正在考虑使用更强大的 zsh 而不是 bash?如果是这样,您可能希望利用流程替换和heredoc。以下代码的工作方式与标题类似。

source <(cat << EOF
command1
command2
EOF
)
于 2021-06-11T05:14:13.900 回答
0

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

a=A

b=B

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

到目前为止没有问题。我得到一个新变量 A_B 存储“某物”

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

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

thing"

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

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

thing\""

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

于 2017-08-09T04:51:20.900 回答