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

时间:2013-07-23 21:17:57

标签: bash shell eval

我正在尝试使用eval评估多行shell命令,但是当我尝试解析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分隔)?

6 个答案:

答案 0 :(得分:8)

\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

这是在长引号列表中的另一个例子,其中重要的是引用变量引用。

答案 1 :(得分: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:

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

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

打印:

a

b
a

b

现在换行保留并解释换行符,而不是eval。

答案 2 :(得分:3)

如果xy变量包含由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

答案 3 :(得分:1)

一种略有不同的方法:

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,也不需要使用subshel​​l。

无用猫的例子:

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

eval "$script"

答案 4 :(得分:0)

在我的FreeBSD框中,我试图用Bourne脚本做一些事情,起初看起来相当微不足道 - 但是我的脑海里浮现了一会儿。由于这个页面是我提到的试图修复我的问题,我将解释我需要做什么以及我是如何完成的:

a=A

b=B

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

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

但是,如果我将作业分散在2行以下:

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

thing"

贝壳向我咆哮说它找不到叫做“东西”的命令。重要的是要理解eval试图将RHS评估为命令。要获得评估RHS作为字符串的eval,您必须将RHS加倍:

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

thing\""

希望这有助于某人。 Manish Jain

答案 5 :(得分:0)

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

source <(cat << EOF
command1
command2
EOF
)