“cat << EOF”如何在 bash 中工作?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2500436/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How does "cat << EOF" work in bash?
提问by hasen
I needed to write a script to enter multi-line input to a program (psql
).
我需要编写一个脚本来向程序 ( psql
)输入多行输入。
After a bit of googling, I found the following syntax works:
经过一番谷歌搜索,我发现以下语法有效:
cat << EOF | psql ---params
BEGIN;
`pg_dump ----something`
update table .... statement ...;
END;
EOF
This correctly constructs the multi-line string (from BEGIN;
to END;
, inclusive) and pipes it as an input to psql
.
这正确构造了多行字符串(从BEGIN;
到END;
,包括)并将其作为输入通过管道传输到psql
。
But I have no idea how/why it works, can some one please explain?
但我不知道它是如何/为什么工作的,有人可以解释一下吗?
I'm referring mainly to cat << EOF
, I know >
outputs to a file, >>
appends to a file, <
reads input from file.
我主要指的是cat << EOF
,我知道>
输出到文件,>>
附加到文件,<
从文件读取输入。
What does <<
exactly do?
具体有什么作用<<
?
And is there a man page for it?
是否有手册页?
采纳答案by kennytm
This is called heredocformatto provide a string into stdin. See https://en.wikipedia.org/wiki/Here_document#Unix_shellsfor more details.
这被称为heredoc格式以将字符串提供给stdin。有关更多详细信息,请参阅https://en.wikipedia.org/wiki/Here_document#Unix_shells。
From man bash
:
来自man bash
:
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 expansion, command substitution, arithmetic expansion, or pathname expansion is performed on word. If any characters in wordare quoted, the delimiteris the result of quote removal on word, and the lines in the here-documentare not expanded. If wordis unquoted, all lines of the here-documentare subjected to parameter expansion, command substitution, and arithmetic expansion. In the latter case, 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.
这里的文件
这种类型的重定向指示 shell 从当前源读取输入,直到看到仅包含单词(没有尾随空格)的行。
然后将读取到该点的所有行用作命令的标准输入。
here-document 的格式为:
<<[-]word here-document delimiter
不会对word执行参数扩展、命令替换、算术扩展或路径名扩展 。如果word中的任何字符被引用,则 分隔符是word上引用删除的结果,并且here-document中的行不会被扩展。如果word 没有被引用,here-document 的所有行都会 进行参数扩展、命令替换和算术扩展。在后一种情况下,字符序列
\<newline>
被忽略,\
必须使用来引用字符\
,$
和`
。如果重定向运算符是
<<-
,则所有前导制表符都将从输入行和包含定界符的行中删除。这允许 shell 脚本中的 here-document 以自然的方式缩进。
回答by Vojtech Vitek
The cat <<EOF
syntax is very useful when working with multi-line text in Bash, eg. when assigning multi-line string to a shell variable, file or a pipe.
cat <<EOF
在 Bash 中处理多行文本时,该语法非常有用,例如。将多行字符串分配给 shell 变量、文件或管道时。
Examples of cat <<EOF
syntax usage in Bash:
cat <<EOF
Bash 中的语法用法示例:
1. Assign multi-line string to a shell variable
1.给shell变量赋值多行字符串
$ sql=$(cat <<EOF
SELECT foo, bar FROM db
WHERE foo='baz'
EOF
)
The $sql
variable now holds the new-line characters too. You can verify with echo -e "$sql"
.
该$sql
变量现在也包含换行符。您可以使用 进行验证echo -e "$sql"
。
2. Pass multi-line string to a file in Bash
2. 将多行字符串传递给 Bash 中的文件
$ cat <<EOF > print.sh
#!/bin/bash
echo $PWD
echo $PWD
EOF
The print.sh
file now contains:
该print.sh
文件现在包含:
#!/bin/bash
echo $PWD
echo /home/user
3. Pass multi-line string to a pipe in Bash
3. 在 Bash 中将多行字符串传递给管道
$ cat <<EOF | grep 'b' | tee b.txt
foo
bar
baz
EOF
The b.txt
file contains bar
and baz
lines. The same output is printed to stdout
.
该b.txt
文件包含bar
和baz
行。相同的输出打印到stdout
.
回答by edelans
In your case, "EOF" is known as a "Here Tag". Basically <<Here
tells the shell that you are going to enter a multiline string until the "tag" Here
. You can name this tag as you want, it's often EOF
or STOP
.
在您的情况下,“EOF”被称为“此处标签”。基本上<<Here
告诉外壳你要输入一个多行字符串,直到 "tag" Here
。您可以根据需要命名此标签,通常为EOF
或STOP
。
Some rules about the Here tags:
关于 Here 标签的一些规则:
- The tag can be any string, uppercase or lowercase, though most people use uppercase by convention.
- The tag will not be considered as a Here tag if there are other words in that line. In this case, it will merely be considered part of the string. The tag should be by itself on a separate line, to be considered a tag.
- The tag should have no leading or trailing spaces in that line to be considered a tag. Otherwise it will be considered as part of the string.
- 标签可以是任何字符串,大写或小写,尽管大多数人按照惯例使用大写。
- 如果该行中有其他词,则该标签不会被视为 Here 标签。在这种情况下,它只会被视为字符串的一部分。标签应单独位于单独的行上,被视为标签。
- 该标签在该行中不应有前导或尾随空格才能被视为标签。否则,它将被视为字符串的一部分。
example:
例子:
$ 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
回答by Andreas Maier
Using tee instead of cat
使用 tee 代替 cat
Not exactly as an answer to the original question, but I wanted to share this anyway: I had the need to create a config file in a directory that required root rights.
不完全是对原始问题的回答,但无论如何我想分享这个:我需要在需要 root 权限的目录中创建一个配置文件。
The following does not work for that case:
以下不适用于这种情况:
$ sudo cat <<EOF >/etc/somedir/foo.conf
# my config file
foo=bar
EOF
because the redirection is handled outside of the sudo context.
因为重定向是在 sudo 上下文之外处理的。
I ended up using this instead:
我最终使用了这个:
$ sudo tee <<EOF /etc/somedir/foo.conf >/dev/null
# my config file
foo=bar
EOF
回答by Andreas Maier
This isn't necessarily an answer to the original question, but a sharing of some results from my own testing. This:
这不一定是原始问题的答案,而是分享我自己测试的一些结果。这个:
<<test > print.sh
#!/bin/bash
echo $PWD
echo $PWD
test
will produce the same file as:
将产生与以下相同的文件:
cat <<test > print.sh
#!/bin/bash
echo $PWD
echo $PWD
test
So, I don't see the point of using the cat command.
所以,我看不出使用 cat 命令的意义。
回答by Yordan Georgiev
Worth noting that here docs work in bash loops too. This example shows how-to get the column list of table:
值得注意的是,这里的文档也适用于 bash 循环。此示例显示如何获取表的列列表:
export postgres_db_name='my_db'
export table_name='my_table_name'
# start copy
while read -r c; do test -z "$c" || echo $table_name.$c , ; done < <(cat << EOF | psql -t -q -d $postgres_db_name -v table_name="${table_name:-}"
SELECT column_name
FROM information_schema.columns
WHERE 1=1
AND table_schema = 'public'
AND table_name =:'table_name' ;
EOF
)
# stop copy , now paste straight into the bash shell ...
output:
my_table_name.guid ,
my_table_name.id ,
my_table_name.level ,
my_table_name.seq ,
or even without the new line
甚至没有新线
while read -r c; do test -z "$c" || echo $table_name.$c , | perl -ne
's/\n//gm;print' ; done < <(cat << EOF | psql -t -q -d $postgres_db_name -v table_name="${table_name:-}"
SELECT column_name
FROM information_schema.columns
WHERE 1=1
AND table_schema = 'public'
AND table_name =:'table_name' ;
EOF
)
# output: daily_issues.guid ,daily_issues.id ,daily_issues.level ,daily_issues.seq ,daily_issues.prio ,daily_issues.weight ,daily_issues.status ,daily_issues.category ,daily_issues.name ,daily_issues.description ,daily_issues.type ,daily_issues.owner
回答by Lefty G Balogh
A little extension to the above answers. The trailing >
directs the input into the file, overwriting existing content. However, one particularly convenient use is the double arrow >>
that appends, adding your new content to the end of the file, as in:
对上述答案的一点扩展。尾随>
将输入定向到文件中,覆盖现有内容。但是,一种特别方便的用法是>>
附加的双箭头,将新内容添加到文件末尾,如下所示:
cat <<EOF >> /etc/fstab
data_server:/var/sharedServer/authority/cert /var/sharedFolder/sometin/authority/cert nfs
data_server:/var/sharedServer/cert /var/sharedFolder/sometin/vsdc/cert nfs
EOF
This extends your fstab
without you having to worry about accidentally modifying any of its contents.
这扩展了您,fstab
而您不必担心意外修改其任何内容。