我需要编写一个脚本,向程序(psql)输入多行输入。

在谷歌搜索了一下之后,我发现下面的语法是有效的:

cat << EOF | psql ---params
BEGIN;

`pg_dump ----something`

update table .... statement ...;

END;
EOF

这正确地构造了多行字符串(从BEGIN;to END;,包括在内)并将其作为输入管道输送到psql。

但是我不知道它是怎么工作的,有人能解释一下吗?

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

<<到底是做什么的?

它有手册页吗?


当前回答

用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

其他回答

这被称为heredoc格式,用于向stdin提供字符串。详情见https://en.wikipedia.org/wiki/Here_document#Unix_shells。


来自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 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. 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.

这并不一定是对最初问题的回答,而是分享我自己测试的一些结果。这样的:

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

将生成与以下相同的文件:

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

所以,我不明白使用cat命令的意义。

对上面的答案做一点扩展。后面的>将输入引导到文件中,覆盖现有内容。然而,一个特别方便的用法是双箭头>>追加,将您的新内容添加到文件的末尾,如:

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

这将扩展fstab,而不必担心意外修改其中的任何内容。

长话短说,EOF标记(但也可以使用不同的文字)是一种heredoc格式,允许您以多行方式提供输入。 很多困惑来自于猫实际上是如何工作的。 你可以使用cat >>或>,如下所示:

$ cat >> temp.txt
line 1
line 2

虽然在手动写入控制台时可以这样使用cat,但如果我想以一种更声明性的方式提供输入,以便工具可以重用它,并保留缩进、空格等,则不方便。 Heredoc允许定义您的整个输入,就好像您不是在使用stdin,而是在单独的文本编辑器中输入一样。这是维基百科文章的意思:

它是源代码文件的一个部分,它被当作 单独的文件中。

值得注意的是,这里的文档也在bash循环中工作。 下面的例子展示了如何获取table的列列表:

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 ,

或者甚至没有新的线条

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