我正在尝试使用 评估多行 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
)?
\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
这是双引号变量引用很重要的一长串案例中的又一个。
您正在将换行符传递给 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
现在换行符由回显保存和解释,而不是评估。
不一定是最佳方式,因为如果x
andy
变量包含由 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
稍微不同的方法:
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"
您是否正在考虑使用更强大的 zsh 而不是 bash?如果是这样,您可能希望利用流程替换和heredoc。以下代码的工作方式与标题类似。
source <(cat << EOF
command1
command2
EOF
)
在我的 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\""
希望这可以帮助某人。马尼什耆那教