shell 中的 <<EOF 和 <<\EOF heredocs 有什么区别

What's the difference between <<EOF and <<\EOF heredocs in shell

我注意到它们之间的几个区别:

<<EOF heredoc 中,无法将新值分配给变量:

bash <<EOF
s=fds
echo $s
EOF

将打印空行,其中

bash <<\EOF
s=fds
echo $s
EOF

将打印变量 s 的值。

全局变量可以在 <<EOF 内访问,但不能在 <<\EOF 内访问(使用 export 可以访问 <<\EOF 内的变量):

s=fds
bash <<EOF
echo $s
EOF

将打印值 fds,其中,

s=fds
bash <<\EOF
echo $s
EOF

将打印空行。

那么它们之间有什么区别,合法的记录行为是什么?

阅读 Advanced Bash Scripting Guide & bash reference manual in particular about redirections:

The format of here-documents is:

<<[-]word
        here-document
delimiter

No parameter and variable expansion, command substitution, arithmetic expansion, or filename expansion is performed on word. If any characters in word are quoted, the delimiter is the result of quote removal on word, and the lines in the here-document are not expanded. If word is unquoted, all lines of the here-document are subjected to parameter expansion, command substitution, and arithmetic expansion, the character sequence \newline is ignored, and ‘\’ must be used to quote the characters ‘\’, ‘$’, and ‘`’.

文档:http://www.gnu.org/software/bash/manual/bash.html#Here-Documents

在您的第一个示例中,定界符未被引号括起来,因此会发生变量扩展,就好像您是 运行 代码

echo "s=fds
echo $s" | bash

在当前 shell 中扩展 $s,其中它是空的。所以新的 shell 看到

s=fds
echo 

来自POSIX spec:

If any character in word is quoted, the delimiter shall be formed by performing quote removal on word, and the here-document lines shall not be expanded. Otherwise, the delimiter shall be the word itself.

所以 <<EOF 版本有 shell 扩展所有变量 运行 这里的文档内容和 <<\EOF (或 <<'EOF'<<EO'F' 等)版本不扩展内容(在这种情况下让 bash 完成这项工作)。

尝试使用 cat 而不是 bash 来更清楚地了解正在发生的事情。

还有 printf '[%s]\n' "$s" and/or 可能 bash -x 而不是 bash:

$ bash -x <<EOF
s=fds
printf '[%s]\n' "$s"
EOF
+ s=fds
+ printf '[%s]\n' ''
[]

$ bash -x <<\EOF
s=fds
printf '[%s]\n' "$s"
EOF
+ s=fds
+ printf '[%s]\n' fds
[fds]