我正在尝试使用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
分隔)?
答案 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)
如果x
和y
变量包含由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,也不需要使用subshell。
无用猫的例子:
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
)