我需要编写脚本以将多行输入输入到程序( psql
)。
经过一番谷歌搜索,我发现以下语法有效:
cat << EOF | psql ---params
BEGIN;
`pg_dump ----something`
update table .... statement ...;
END;
EOF
这样可以正确构造多行字符串(从BEGIN;
到END;
,包括两端),并将其作为输入传递给psql
。
但是我不知道它如何/为什么起作用,请解释一下吗?
我主要是指cat << EOF
,我知道>
输出到文件, >>
追加到文件, <
从文件读取输入。
<<
到底是做什么的?
并且有手册页吗?
#1楼
当在Bash中处理多行文本时, cat <<EOF
语法非常有用。 将多行字符串分配给shell变量,文件或管道时。
Bash中cat <<EOF
语法用法的示例:
1.将多行字符串分配给shell变量
$ sql=$(cat <<EOF
SELECT foo, bar FROM db
WHERE foo='baz'
EOF
)
现在, $sql
变量也包含换行符。 您可以使用echo -e "$sql"
进行验证。
2.将多行字符串传递到Bash中的文件
$ cat <<EOF > print.sh
#!/bin/bash
echo \$PWD
echo $PWD
EOF
现在, print.sh
文件包含:
#!/bin/bash
echo $PWD
echo /home/user
3.将多行字符串传递到Bash中的管道
$ cat <<EOF | grep 'b' | tee b.txt
foo
bar
baz
EOF
b.txt
文件包含bar
和baz
行。 将相同的输出打印到stdout
。
#2楼
这称为heredoc 格式,以将字符串提供给stdin。 有关更多详细信息,请参见https://en.wikipedia.org/wiki/Here_document#Unix_shells 。
来自man bash
:
这里文件
这种重定向指示外壳程序从当前源读取输入,直到看到仅包含单词(无尾随空格)的行。
直到该点为止的所有行都将用作命令的标准输入。
此处文档的格式为:
<<[-]word here-document delimiter
没有对word执行参数扩展,命令替换,算术扩展或路径名扩展。 如果对word中的任何字符加引号,则定界符是对word删除引号的结果,并且本文档中的行不会扩展。 如果未引用word ,则此文档的所有行都将进行参数扩展,命令替换和算术扩展。 在后一种情况下,字符序列
\\<newline>
被忽略,并且必须使用\\
来引用字符\\
,$
和`
。如果重定向运算符是
<<-
,则从输入行和包含定界符的行中除去所有前导制表符 。 这允许外壳脚本中的此处文档以自然方式缩进。
#3楼
在您的情况下,“ EOF”被称为“此处标签”。 基本上, <<Here
告诉外壳程序您将要输入多行字符串,直到“ tag” Here
为止。 您可以根据需要命名此标签,通常是EOF
或STOP
。
有关Here标记的一些规则:
- 标签可以是任何字符串,可以是大写或小写,尽管大多数人习惯上都使用大写。
- 如果该行中还有其他单词,则该标签将不被视为Here标签。 在这种情况下,它将仅被视为字符串的一部分。 标签本身应位于单独的行上,才能视为标签。
- 标签在该行中不应包含任何前导或尾随空格,才能将其视为标签。 否则,它将被视为字符串的一部分。
例:
$ 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
#4楼
POSIX 7
kennytm引用了man bash
,但是其中大多数也是POSIX 7: http ://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_07_04:
重定向操作符“ <<”和“ <<-”都允许将外壳程序输入文件(称为“ here-document”)中包含的行重定向到命令的输入。
此处文档应被视为一个单词,该单词从下一个单词开始,一直持续到一行仅包含定界符和a,且中间没有字符。 然后,下一个此处文档开始(如果有)。 格式如下:
[n]<<word here-document delimiter
其中可选的n表示文件描述符号。 如果省略该数字,则本文参考标准输入(文件描述符0)。
如果在单词中引用了任何字符,则应通过对单词执行引号删除来形成分隔符,并且此处文档行不得扩展。 否则,定界符应为单词本身。
如果单词中没有引用任何字符,则应扩展本文档的所有行,以进行参数扩展,命令替换和算术扩展。 在这种情况下,输入中的in表现为内部双引号(请参见Double-Quotes)。 但是,除非在“ $()”,“``''或“ $ {}”中出现双引号,否则本文中的双引号字符('“')不应作特殊处理。
如果重定向符号为“ <<-”,则应从输入行和包含尾部定界符的行中删除所有前导的
<tab>
字符。 如果在一行上指定了多个“ <<”或“ <<-”运算符,则与第一个运算符关联的此处文档应由应用程序首先提供,并由外壳程序首先读取。当从终端设备读取此处文档并且外壳是交互式的时,它将在读取输入的每一行之前将按外壳变量中所述进行处理的变量PS2的内容写入标准错误,直到识别出定界符为止。
例子
一些例子尚未给出。
引号防止参数扩展
不带引号:
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
缩进。 kes。
#5楼
使用tee代替cat
并非完全是对原始问题的答案,但是我还是想分享一下:我需要在需要根权限的目录中创建配置文件。
以下情况不适用于这种情况:
$ sudo cat <<EOF >/etc/somedir/foo.conf
# my config file
foo=bar
EOF
因为重定向是在sudo上下文之外处理的。
我最终改用了这个:
$ sudo tee <<EOF /etc/somedir/foo.conf >/dev/null
# my config file
foo=bar
EOF
来源:oschina
链接:https://my.oschina.net/stackoom/blog/3156309