简体   繁体   English

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

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

I found a great answer for how to comment in bash script (by @sunny256 ):我找到了一个关于如何在 bash 脚本中评论的好答案( @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. END分隔符周围的''很重要,否则块内的内容(例如$(command)将被解析并执行。

This may be ugly, but it works and I'm keen to know what it means.这可能很难看,但它有效,我很想知道它的含义。 Can anybody explain it simply?谁能简单解释一下? I did already find an explanation for : that it is no-op or true.我确实已经找到了一个解释:它是无操作或真实的。 But it does not make sense to me to call no-op or true anyway....但无论如何,调用 no-op 或 true 对我来说是没有意义的......

I'm afraid this explanation is less "simple" and more "thorough", but here we go.恐怕这种解释不那么“简单”而更“彻底”,但我们开始吧。

The goal of a comment is to be text that is not interpreted or executed as code.注释的目标是作为代码解释或执行的文本。

Originally, the UNIX shell did not have a comment syntax per se .最初,UNIX shell本身没有注释语法。 It did, however, have the null command : (once an actual binary program on disk, /bin/: ), which ignores its arguments and does nothing but indicate successful execution to the calling shell.然而,它确实有一个空命令:曾经是磁盘上的一个实际二进制程序, /bin/: :),它忽略它的参数并且除了指示调用 shell 成功执行之外什么都不做。 Effectively, it's a synonym for true that looks like punctuation instead of a word, so you could put a line like this in your script:实际上,它是true的同义词,看起来像标点符号而不是单词,因此您可以在脚本中添加这样的一行:

: This is a comment

It's not quite a traditional comment;这不是一个传统的评论。 it's still an actual command that the shell executes.它仍然是 shell 执行的实际命令。 But since the command doesn't do anything, surely it's close enough: mission accomplished!但既然命令什么都不,肯定它已经足够接近了:任务完成了! Right?正确的?

The problem is that the line is still treated as a command beyond simply being run as one.问题是该行仍然被视为一个命令,而不仅仅是作为一个命令运行。 Most importantly, lexical analysis - parameter substitution, word splitting, and such - still takes place on those destined-to-be-ignored arguments.最重要的是,词法分析——参数替换、分词等——仍然发生在那些注定要被忽略的论点上。 Such processing means you run the risk of a syntax error in a "comment" crashing your whole script:这样的处理意味着您冒着在“注释”中出现语法错误的风险,从而使整个脚本崩溃:

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

That problem led to the introduction of a genuine comment syntax: the now-familiar # (which was first introduced in the C shell created at BSD).这个问题导致引入了真正的注释语法:现在熟悉的# (它首先在 BSD 创建的 C shell 中引入)。 Everything from # to the end of the line is completely ignored by the shell, so you can put anything you like there without worrying about syntactic validity:#到行尾的所有内容都被 shell 完全忽略,所以你可以放任何你喜欢的东西,而不用担心语法有效性:

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

And that's How The Shell Got Its Comment Syntax .这就是Shell 获得注释语法的方式。

However, you were looking for a multi-line (block) comment, of the sort introduced by /* (and terminated by */ ) in C or Java.但是,您正在寻找 C 或 Java 中由/* (并由*/终止)引入的那种多行(块)注释。 Unfortunately, the shell simply does not have such a syntax.不幸的是,shell 根本没有这样的语法。 The normal way to comment out a block of consecutive lines - and the one I recommend - is simply to put a # in front of each one.注释掉连续行块的正常方法——也是我推荐的方法——只是在每行前面放一个# But that is admittedly not a particularly "multi-line" approach.但这无疑不是一种特别“多线”的方法。

Since the shell supports multi-line string-literals, you could just use : with such a string as an argument:由于 shell 支持多行字符串文字,您可以使用:将这样的字符串作为参数:

: 'So
this is all
a "comment"
'

But that has all the same problems as single-line : .但这与单行:具有所有相同的问题。 You could also use backslashes at the end of each line to build a long command line with multiple arguments instead of one long string, but that's even more annoying than putting a # at the front, and more fragile since trailing whitespace breaks the line-continuation.您还可以在每行的末尾使用反斜杠来构建一个带有多个参数而不是一个长字符串的长命令行,但这比在前面放置#更烦人,而且更脆弱,因为尾随空格会破坏行继续.

The solution you found uses what is called a here-document .您找到的解决方案使用所谓的here-document The syntax some-command <<whatever causes the following lines of text - from the line immediately after the command, up to but not including the next line containing only the text whatever - to be read and fed as standard input to some-command .语法some-command <<whatever导致以下文本行 - 从命令之后的行开始,直到但不包括仅包含文本whatever下一行 - 被读取并作为标准输入提供给some-command Here's an alternate shell implementation of "Hello, world" which takes advantage of this feature:这是“Hello, world”的另一个 shell 实现,它利用了这个特性:

cat <<EOF
Hello, world
EOF

If you replace cat with our old friend : , you'll find that it ignores not only its arguments but also its input: you can feed whatever you want to it, and it will still do nothing (and still indicate that it did that nothing successfully).如果你将cat替换为我们的老朋友: ,你会发现它不仅忽略了它的参数,还忽略了它的输入:你可以给它任何你想要的东西,它仍然什么都不做(并且仍然表明它什么也没做成功地)。

However, the contents of a here-document do undergo string processing.但是,here-document 的内容会经过字符串处理。 So just as with the single-line : comment, the here-document version runs the risk of syntax errors inside what is not meant to be executable code:因此,就像单行:注释一样,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 `

The solution, as seen in the code you found, is to quote the end-of-document "sentinel" (the EOF or END or whatever) on the line introducing the here document (eg <<'EOF' ).如您找到的代码所示,解决方案是在介绍此处文档的行(例如<<'EOF' )上引用文档结尾“哨兵”( EOFEND或其他)。 Doing this causes the entire body of the here-document to be treated as literal text - no parameter expansion or other processing occurs.这样做会导致 here-document 的整个正文被视为文字文本 - 不会发生参数扩展或其他处理。 Instead, the text is fed to the command unchanged, just as if it were being read from a file.相反,文本原封不动地馈送到命令中,就好像它是从文件中读取的一样。 So, other than a line consisting of nothing but the sentinel, the here-document can contain any characters at all:因此,除了只包含哨兵的一行之外,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 is worth noting that the way you quote the sentinel doesn't matter - you can use <<'EOF' , <<E"OF" , or even <<EO\F ; all have the same result. This is different from the way here-documents work in some other languages, such as Perl and Ruby, where the content is treated differently depending on the way the sentinel is quoted.) (值得注意的是,你引用哨兵的方式并不重要 - 你可以使用<<'EOF'<<E"OF" ,甚至<<EO\F ; 都具有相同的结果。这是不同的从 here-documents 在其他一些语言(例如 Perl 和 Ruby)中的工作方式来看,根据引用标记的方式,对内容的处理方式不同。)

Notwithstanding any of the above, I strongly recommend that you instead just put a # at the front of each line you want to comment out.尽管有上述任何一项,我强烈建议您只在要注释掉的每一行的前面加上一个# Any decent code editor will make that operation easy - even plain old vi - and the benefit is that nobody reading your code will have to spend energy figuring out what's going on with something that is, after all, intended to be documentation for their benefit.任何体面的代码编辑器都会使该操作变得容易 - 即使是普通的旧vi - 好处是没有人阅读您的代码将不得不花费精力来弄清楚到底发生了什么事情,这些事情毕竟是为了他们的利益而编写的文档。

It is called a Here Documen t.它被称为Here Documen t。 It is a code block that lets you send a list of commands to another command or program它是一个代码块,可让您将命令列表发送到另一个命令或程序

The string following the << is the marker determining the end of the block. <<后面的字符串是确定块结束的标记。 If you send commands to no-op, nothing happens, which is why you can use it as a comment block.如果您向 no-op 发送命令,则不会发生任何事情,这就是您可以将其用作注释块的原因。

That's heredoc syntax.这是heredoc语法。 It's a way of defining multi-line string literals.这是一种定义多行字符串文字的方法。

As the answer at your link explains, the single quotes around the END disables interpolation, similar to the way single-quoted strings disable interpolation in regular bash strings.正如您链接中的答案所解释的那样, END 周围的单引号会禁用插值,类似于单引号字符串禁用常规 bash 字符串中的插值的方式。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM