shell 如何在bash中使用:〈'END '来创建多行注解块?

bjp0bcyl  于 2023-03-24  发布在  Shell
关注(0)|答案(3)|浏览(141)

我找到了一个关于如何comment in bash script的很好的答案(通过@sunny256):

#!/bin/bash
echo before comment
: <<'END'
bla bla
blurfl
END
echo after comment

END分隔符周围的''很重要,否则块内的东西(例如$(command))将被解析和执行。
这可能是丑陋的,但它的工作原理,我很想知道它的意思。有人能简单地解释一下吗?我已经找到了:的解释,它是无操作或真的。但它没有意义,我呼吁无操作或真的反正...

rpppsulh

rpppsulh1#

这个解释恐怕不那么“简单”,更“透彻”,但我们来看看。
注解的目标是成为一个不被解释或执行为代码的文本。
最初,UNIXshell本身没有注解语法 *,但是它有空命令:(曾经是磁盘上的一个实际的二进制程序/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中首次亮相,然后被借用回vanilla sh)。从#到行尾的所有内容都被shell完全忽略,所以你可以在那里放任何你喜欢的东西,而不用担心语法的有效性:

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

这就是 * Shell如何获得其注解语法 *。
但是你要找的是多行(块)注解,由/*引入的类型(并由*/终止)。不幸的是,shell根本没有这样的语法。注解掉一个连续行块的正常方法--也是我推荐的方法--只是在每一行前面放一个#。但无可否认,这不是一个特别“多线”的方法。
由于shell支持多行字符串文字,您可以使用:,并将这样的字符串作为参数:

: 'So
this is all
a "comment"
'

但这与单行:有着相同的问题,你也可以在每行的末尾使用反斜杠来构建一个包含多个参数的长命令行,而不是一个长字符串,但这比在前面放一个#更烦人,而且更脆弱,因为尾随的空格会破坏行的连续性。
您找到的解决方案使用了所谓的here-document。语法some-command <<whatever导致以下文本行-从紧接在命令之后的行,直到但不包括仅包含文本whatever的下一行-被读取并作为标准输入馈送到some-command。下面是“Hello,世界”,它利用了这个功能:

cat <<EOF
Hello, world
EOF

如果你用我们的老朋友:替换cat,你会发现它不仅忽略了参数,还忽略了输入:你可以向它提供任何你想要的东西,它仍然不会做任何事情(并且仍然表明它没有成功地做任何事情)。
然而,here-document的内容会经过字符串处理。因此,就像单行:注解一样,here-document版本在不应该是可执行代码的代码中存在语法错误的风险:

#!/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 `

解决方案,如您找到的代码中所示,是引用文档结尾的“sentinel”(EOFEND或其他)在介绍here文档的行上(例如<<'EOF')。这样做会导致here-document的整个主体被视为文字文本-没有参数扩展或其他处理发生。文本被原封不动地提供给命令,就像从文件中读取一样。因此,除了一行只包含sentinel之外,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.

(It值得注意的是,您引用sentinel的方式并不重要-您可以使用<<'EOF'<<E"OF",甚至<<EO\F;都有相同的结果。这与其他一些语言中的here-documents的工作方式不同,例如Perl和Ruby,其中内容的处理方式取决于sentinel的引用方式。)
尽管有以上这些,我还是强烈建议你在你想注解掉的每一行的前面放一个#。任何像样的代码编辑器都会让这个操作变得简单--即使是普通的旧vi--好处是没有人阅读你的代码会花精力去弄清楚到底发生了什么,毕竟,旨在成为有利于他们的文档。

a14dhokn

a14dhokn2#

它被称为Here Documen t。它是一个代码块,允许您将命令列表发送到另一个命令或程序
<<后面的字符串是决定块结束的标记。如果你向no-op发送命令,什么也不会发生,这就是为什么你可以把它用作注解块。

ruarlubt

ruarlubt3#

这是heredoc语法。它是一种定义多行字符串文字的方法。
正如链接中的答案所解释的那样,END周围的单引号禁用插值,类似于单引号字符串禁用常规bash字符串中的插值。

相关问题