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

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

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

`pg_dump ----something`

update table .... statement ...;

END;
EOF

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

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

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

<<到底是做什么的?

它有手册页吗?


当前回答

<< EoF的基本意思是:

<< - "读取从下一行开始的多行输入,并将其视为单独文件中的代码"

EoF -“在多行输入中发现单词EoF后立即停止阅读”

正如其他答案所解释的,多行输入称为Here文档

Here Document通常用于生成要传递给后续进程的输出。例如,cat << EoF可以使用Here Document生成所需的输出。

下面是一个使用Here Document动态创建文本文档的例子:

cat << EoF > ./my-document.txt
Hello world
Have a nice day
EoF

其他回答

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

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的基本意思是:

<< - "读取从下一行开始的多行输入,并将其视为单独文件中的代码"

EoF -“在多行输入中发现单词EoF后立即停止阅读”

正如其他答案所解释的,多行输入称为Here文档

Here Document通常用于生成要传递给后续进程的输出。例如,cat << EoF可以使用Here Document生成所需的输出。

下面是一个使用Here Document动态创建文本文档的例子:

cat << EoF > ./my-document.txt
Hello world
Have a nice day
EoF

创建json文件的示例:

cat << EoF > ./allaccess.json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "s3:*"
      ],
      "Resource": [
        "arn:aws:s3:::*"
      ]
    }
  ]
}
EoF

结果是:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "s3:*"
      ],
      "Resource": [
        "arn:aws:s3:::*"
      ]
    }
  ]
}

在你的例子中,“EOF”被称为“Here Tag”。基本上,<<Here告诉shell,您将输入一个多行字符串,直到“tag”在这里。你可以随意命名这个标签,通常是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

值得注意的是,这里的文档也在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