: <<'END' 如何在 bash 中工作以创建多行注释块?

How does : <<'END' work in bash to create a multi-line comment block?

我找到了如何 comment in bash script (by @sunny256):

的好答案
#!/bin/bash
echo before comment
: <<'END'
bla bla
blurfl
END
echo after comment

The ' and ' around the END delimiter are important, otherwise things inside the block like for example $(command) will be parsed and executed.

这可能很难看,但它确实有效,我很想知道它的含义。谁能简单解释一下?我确实已经找到了 : 的解释,它是空操作或 true。但无论如何调用 no-op 或 true 对我来说没有意义....

这是 heredoc 语法。这是一种定义多行字符串文字的方法。

正如您 link 的回答所解释的那样,END 周围的单引号会禁用插值,类似于单引号字符串在常规 bash 字符串中禁用插值的方式。

它被称为 Here Document。它是一个代码块,可让您将命令列表发送到另一个命令或程序

<<后面的字符串是确定块结束的标记。如果您向 no-op 发送命令,则什么也不会发生,这就是为什么您可以将其用作注释块的原因。

恐怕这个解释不太“简单”而更“透彻”,但我们开始吧。

评论的目标是作为代码解释或执行的文本。

最初,UNIX shell 本身没有注释语法 。然而,它确实有空命令 :(曾经是磁盘上的实际二进制程序,/bin/:),它忽略了它的参数,除了向调用 shell 指示成功执行之外什么都不做。实际上,它是 true 的同义词,看起来像标点符号而不是单词,因此您可以在脚本中添加如下一行:

: This is a comment

这不是很传统的评论;它仍然是 shell 执行的实际命令。但是由于该命令没有 任何事情,所以它肯定足够接近:任务完成!对吧?

问题在于该行仍然被视为一个命令,而不仅仅是 运行 作为一个命令。最重要的是,词法分析——参数替换、分词等——仍然发生在那些注定要被忽略的参数上。这样的处理意味着您 运行 存在“注释”中的语法错误导致整个脚本崩溃的风险:

 : Now let's see what happens next
 echo "Hello, world!"
 #=> hello.sh: line 1: unexpected EOF while looking for matching `''

这个问题导致引入了真正的注释语法:现在熟悉的 #(以前在 BSD 创建的 C shell 中引入)。从 # 到行尾的所有内容都被 shell 完全忽略,所以你可以把任何你喜欢的东西放在那里而不用担心句法有效性:

 # Now let's see what happens next
 echo "Hello, world!"
 #=> Hello, world!

这就是 Shell 的注释语法

但是,您正在寻找由 /*(并由 */ 终止)在 C 或 Java 中引入的多行(块)注释。不幸的是,shell 根本没有这样的语法。注释掉一组连续行的正常方法——也是我推荐的方法——只是在每行前面放一个 #。但不可否认,这并不是一种特别“多线”的方法。

由于 shell 支持多行字符串文字,您可以使用 : 并将这样的字符串作为参数:

: 'So
this is all
a "comment"
'

但这与单行 : 存在所有相同的问题。您还可以在每一行的末尾使用反斜杠来构建一个包含多个参数而不是一个长字符串的长命令行,但这比在前面放置 # 更烦人,而且更脆弱,因为尾随空格中断行继续。

您找到的解决方案使用了所谓的 here-document。语法 some-command <<whatever 导致以下文本行 - 从紧跟在命令之后的行开始,直到但不包括仅包含文本 whatever 的下一行 - 被读取并作为标准输入提供给 some-command。这是利用此功能的“Hello, world”的替代 shell 实现:

cat <<EOF
Hello, world
EOF

如果你用我们的老朋友 : 替换 cat,你会发现它不仅忽略了它的参数,也忽略了它的输入:你可以给它任何你想要的东西,它仍然什么都不做(并且仍然表明它没有成功)。

但是,here-document 的内容确实经过了字符串处理。因此,就像单行 : 注释一样,这里的文档版本 运行s 在不应该是可执行代码的内容中存在语法错误的风险:

#!/bin/sh -e 
: <<EOF
(This is a backtick: `)
EOF
echo 'In modern shells, $(...) is preferred over backticks.'
#=> ./demo.sh: line 2: bad substitution: no closing "`" in `

如您找到的代码所示,解决方案是在介绍此处的行中引用文档结尾的“哨兵”(EOFEND 或其他)文档(例如 <<'EOF')。这样做会导致 here-document 的整个正文被视为文字文本 - 不会发生参数扩展或其他处理。相反,文本被原封不动地提供给命令,就好像它是从文件中读取的一样。所以,除了一行只包含标记之外,这里的文档可以包含任何字符:

#!/bin/sh -e
: <<'EOF'
This is a backtick: `
EOF
echo 'In modern shells, $(...) is preferred over backticks.'
#=> In modern shells, $(...) is preferred over backticks.

(值得注意的是,你引用哨兵的方式并不重要——你可以使用<<'EOF'<<E"OF",甚至<<EO\F; 都具有相同的结果。这与 here-documents 在某些其他语言中的工作方式不同,例如 Perl 和 Ruby,其中根据引用标记的方式对内容进行不同的处理.)

尽管有上述任何一种情况,我还是强烈建议您在要注释掉的每一行的前面加上一个 #。任何体面的代码编辑器都会使该操作变得容易 - 甚至是普通的旧 vi - 好处是没有人阅读你的代码将不得不花费精力来弄清楚那些本来打算成为文档的东西到底发生了什么为了他们的利益。