Bash中heredoc的输入语法

5

我目前正在学习Unix bash,通过Ubuntu 16终端。我正在编写一个简单的脚本,以便练习编写Unix代码。以下是代码示例:

report_uptime(){
cat << _EOF_
    <H2>System Uptime</H2>
    <PRE>$(uptime)</PRE>
    _EOF_
return
}

这段代码无法正常工作的原因是,在使用cat之后,我应该使用<<-而不是<<。有时候<<会起作用,那么我什么时候应该使用<<,什么时候应该使用<<-呢?

下面这段代码可以正常工作:

report_uptime(){
cat <<- _EOF_
    <H2>System Uptime</H2>
    <PRE>$(uptime)</PRE>
    _EOF_
return
}

你能添加一个测试示例吗? - Marcus Müller
你确定在 <<_EOF_ 之间可以有空格吗? - Marcus Müller
你也可以说明这是哪种编程语言或shell。bash?dash?ksh? - Robert
好的,这是一个函数,我已经让它工作了。唯一的问题是<<应该是<<-。问题不在于为什么这不起作用,而是何时使用<<和何时使用<<-?我正在使用bash。 - John
3个回答

6
这并不是猫语法,而是您的shell支持的重定向运算符之一:

https://www.gnu.org/software/bash/manual/bashref.html#Here-Documents

3.6.6 Here Documents

This type of redirection instructs the shell to read input from the current source until a line containing only word (with no trailing blanks) is seen. All of the lines read up to that point are then used as the standard input for a command.

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 ‘`’.

If the redirection operator is ‘<<-’, then all leading tab characters are stripped from input lines and the line containing delimiter. This allows here-documents within shell scripts to be indented in a natural fashion.


1
请确保您注意最后一行中的“制表符”一词。实际上,这只会删除制表符,而不是空格。 - Taywee
这很有道理。当我没有[-]时,它将脚本的其余部分视为字符串。 - John

5
这并不是严格意义上关于cat工具的语法,而是关于shell本身的语法,即bash
你正在使用的结构被称为“here-document”。一个here-document将其内容提供给你在<<之前放置的任何命令的标准输入。
语法如下:
command <<word
...
contents
...
END_TAG

这里的word是与END_TAG完全相同,或者可能是'END_TAG'-END_TAG-'END_TAG'

  • END_TAG: Without single quotes, the contents of the here-document will undergo substitution. This means that any variable, or simply put, "anything that contains a $" will be replaced with its value.

    $ tr 'a-z' 'A-Z' <<TR_END
    > This is my $HOME
    > TR_END
    THIS IS MY /USERS/KK
    

    (The >, a greater-than sign and a space, is what's called the secondary prompt. I get that because I'm typing this directly into the shell, and it needs more lines of input before it can execute the whole command. It is not typed by me.)

  • 'END_TAG': With single quotes, the contents of the here-document will not undergo substitution. This means, for example, that if you write $HOME in the here-document, it will be fed into the command just like that, not like /home/myname (or whatever your home directory may be).

    $ tr 'a-z' 'A-Z' <<'TR_END'
    > This is my $HOME
    > TR_END
    THIS IS MY $HOME
    
  • With a leading dash (-), the shell will strip off all tabs (but not spaces) at the start of each line of the here-document, including the line with the END_TAG at the end.

    $ tr 'a-z' 'A-Z' <<-TR_END
    >       This line has a tab.
    > This one does not.
    > TR_END
    THIS LINE HAS A TAB.
    THIS ONE DOES NOT.
    
  • Without a leading dash, the shell will not strip off tabs. The END_TAG needs to be the first (and only) thing on the line ending the here-document.

    $ tr 'a-z' 'A-Z' <<TR_END
    >       This line has a tab.
    > This one does not.
    > TR_END
        THIS LINE HAS A TAB.
    THIS ONE DOES NOT.
    

bash shell还有一种称为“here-strings”的东西。 它的工作方式类似,但您只需要将单个行输入到命令中:

command <<<word

例如:

$ tr 'a-z' 'A-Z' <<<"hello world!"
HELLO WORLD!

2

通常,结束标记不应缩进。将其移动到第1列。同时删除return语句,这在bash中对我有效。


底部的代码可行。我的问题不是“为什么我的代码不起作用?”而是,我何时使用<<和何时使用<<-,因为在这个函数的情况下,<<将无法工作,但<<-可以。 - John

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接