“猫”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 )
$sql
variables现在也包含换行符。 你可以使用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
文件包含bar
和baz
行。 相同的输出打印到stdout
。
在你的情况下,“EOF”被称为“这里标签”。 基本上<<Here
告诉shell,你要input一个多行string,直到“标记” Here
。 您可以根据需要命名该标签,通常是EOF
或STOP
。
关于Here标签的一些规则:
- 标签可以是任何string,大写或小写,尽pipe大多数人按照惯例使用大写字母。
- 如果该行中有其他单词,该标签将不被视为“Here”标签。 在这种情况下,它只会被视为string的一部分。 标签本身应该在一个单独的行上,被视为一个标签。
- 该标签在该行中应该没有前导空格或尾随空格才能被视为标签。 否则,它将被视为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