“猫”EOF“如何在bash中工作?

我需要编写一个脚本来input一个程序( psql )的多行input。

经过一番search后,我发现下面的语法工作:

 cat << EOF | psql ---params BEGIN; `pg_dump ----something` update table .... statement ...; END; EOF 

这正确地构造了多行string(从BEGIN;END; ,包括在内)并将其作为psql的input。

但我不知道如何/为什么它的工作,请解释一下吗?

我主要是指cat << EOF ,我知道>输出到一个文件, >>附加到一个文件, <从文件读取input。

<<究竟是做什么的?

有没有一个人的网页?

这被称为heredoc格式来提供一个string到标准input。 有关更多详细信息,请参阅https://en.wikipedia.org/wiki/Here_document#Unix_shells


man bash

这里的文件

这种types的redirect指示shell从当前源读取input,直到看到仅包含单词(没有尾随空白)的行。

所有读到这一点的行然后被用作命令的标准input。

这里的文件格式是:

  <<[-]word here-document delimiter 

执行参数扩展,命令replace,算术扩展或path名扩展。 如果单词中的任何字符被引用,则分隔符是对单词的引用删除的结果,并且这里的文档中的行不被扩展。 如果单词不加引号,那么这里的文档的所有行都要进行参数扩展,命令replace和算术扩展。 在后一种情况下,字符序列\<newline>被忽略, \必须用于引用字符\$`

如果redirect操作符为<<- ,则所有前导制表符都从input行和包含分隔符的行中剥离。 这允许在这里 – shell脚本中的文档以自然的方式缩进。

cat <<EOF语法在使用Bash中的多行文本时非常有用,例如。 将多行string分配给shellvariables,文件或pipe道时。

cat <<EOF语法在Bash中的用法示例:

1.将多行string分配给shellvariables

 $ sql=$(cat <<EOF SELECT foo, bar FROM db WHERE foo='baz' EOF ) 

$sqlvariables现在也包含换行符。 你可以使用echo -e "$sql"进行validation。

2.将多行string传递给Bash中的文件

 $ cat <<EOF > print.sh #!/bin/bash echo \$PWD echo $PWD EOF 

print.sh文件现在包含:

 #!/bin/bash echo $PWD echo /home/user 

3.将多行string传递给Bash中的pipe道

 $ cat <<EOF | grep 'b' | tee b.txt foo bar baz EOF 

b.txt文件包含barbaz行。 相同的输出打印到stdout

在你的情况下,“EOF”被称为“这里标签”。 基本上<<Here告诉shell,你要input一个多行string,直到“标记” Here 。 您可以根据需要命名该标签,通常是EOFSTOP

关于Here标签的一些规则:

  1. 标签可以是任何string,大写或小写,尽pipe大多数人按照惯例使用大写字母。
  2. 如果该行中有其他单词,该标签将不被视为“Here”标签。 在这种情况下,它只会被视为string的一部分。 标签本身应该在一个单独的行上,被视为一个标签。
  3. 该标签在该行中应该没有前导空格或尾随空格才能被视为标签。 否则,它将被视为string的一部分。

例:

 $ cat >> test <<HERE > Hello world HERE <--- Not by itself on a separate line -> not considered end of string > This is a test > HERE <-- Leading space, so not considered end of string > and a new line > HERE <-- Now we have the end of the string 

POSIX 7

kennytm引用了man bash ,但大部分也是POSIX 7: http ://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_07_04:

redirect操作符“<<”和“<< – ”都允许将包含在shellinput文件中的行(称为“here-document”)redirect到命令的input。

这里的文件应该被视为一个单词,在下一个单词之后开始,直到有一行只包含分隔符和a,而没有中间的字符。 然后下一个文件开始,如果有的话。 格式如下:

 [n]<<word here-document delimiter 

其中可选的n表示文件描述符编号。 如果省略号码,则这里的文件是指标准input(文件描述符0)。

如果引用字中的任何字符,则通过对字进行引号删除来形成分隔符,并且这里的文件行不应被扩展。 否则,分隔符应该是这个词本身。

如果没有引用单词中的任何一个字符,那么这里的文档的所有行都应该被扩展用于参数扩展,命令replace和算术扩展。 在这种情况下,input内部的双引号(参见双引号)。 但是,除非双引号出现在“$()”,“`”或“$ {}”中,否则双引号字符('“')不应该在here-document中专门处理。

如果redirect符号是“<< – ”,则应从input行和包含尾随分隔符的行中剥离所有前导<tab>字符。 如果在一行中指定了多个“<<”或“<< – ”运算符,则与第一个运算符关联的here-document应由应用程序首先提供,并应由shell首先读取。

当从terminal设备读取文档并且shell是交互式的时,在读取每行input之前,应该将variablesPS2的内容写入标准错误,直到分隔符被识别为止。

例子

还没有给出一些例子。

引号防止参数扩展

没有引号:

 a=0 cat <<EOF $a EOF 

输出:

 0 

用引号:

 a=0 cat <<'EOF' $a EOF 

或(丑陋但有效):

 a=0 cat <<E"O"F $a EOF 

输出:

 $a 

连字符删除前面的标签

没有连字符:

 cat <<EOF <tab>a EOF 

其中<tab>是一个文字标签,可以用Ctrl + V <tab>插入

输出:

 <tab>a 

连字符:

 cat <<-EOF <tab>a <tab>EOF 

输出:

 a 

这当然存在,所以你可以缩进你的cat像周围的代码,这是更容易阅读和维护。 例如:

 if true; then cat <<-EOF a EOF fi 

不幸的是,这不适用于空间字符:这里POSIX喜欢tab缩进。 让人惊讶。

用发球而不是猫

不完全是对原始问题的回答,但我仍想分享:我需要在需要root权限的目录中创buildconfiguration文件。

以下情况不适用于这种情况:

 $ sudo cat <<EOF >/etc/somedir/foo.conf # my config file foo=bar EOF 

因为redirect是在sudo上下文之外处理的。

我结束了使用它,而不是:

 $ sudo tee <<EOF /etc/somedir/foo.conf >/dev/null # my config file foo=bar EOF