添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

"cat << EOF "在bash中如何工作?

931 人关注

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

经过一番谷歌搜索,我发现下面的语法很有效。

cat << EOF | psql ---params
BEGIN;
`pg_dump ----something`
update table .... statement ...;

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

但我不知道它是如何/为什么工作的,谁能解释一下?

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

替换代码9】到底是做什么的?

是否有一个关于它的手册页面?

4 个评论
这可能是对 cat 的无用使用。试试 psql ... << EOF ... 。 请参阅 "这里的字符串"。 mywiki.wooledge.org/BashGuide/InputAndOutput?#Here_Strings
Alex
I'm surprised it works with cat but not with echo. cat should expect a file name as stdin, not a char string. psql << EOF sounds logical, but not othewise. Works with cat but not with echo. Strange behaviour. Any clue about that?
Alex
Answering to myself: cat without parameters executes and replicates to the output whatever send via input (stdin), hence using its output to fill the file via >. In fact a file name read as a parameter is not a stdin stream.
@Alex echo只是打印它的命令行参数,而 cat 读取stding(当管道到它时)或读取与它的命令行参数相对应的文件。
linux
bash
scripting
heredoc
hasen
hasen
发布于 2010-03-23
12 个回答
Vojtech Vitek
Vojtech Vitek
发布于 2018-08-14
已采纳
0 人赞同

在Bash中处理多行文本时, cat <<EOF 语法非常有用,例如,当把多行字符串分配给shell变量、文件或管道时。

Examples of cat <<EOF syntax usage in Bash:

1. Assign multi-line string to a shell variable

$ sql=$(cat <<EOF
SELECT foo, bar FROM db
WHERE foo='baz'

现在,$sql变量也持有换行字符。你可以用echo -e "$sql"来验证。

2. Pass multi-line string to a file in Bash

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

现在的print.sh文件包含。

#!/bin/bash
echo $PWD
echo /home/user

3. Pass multi-line string to a pipe in Bash

$ cat <<EOF | grep 'b' | tee b.txt

b.txt文件包含barbaz行。同样的输出被打印到stdout

1.1和3可以不用猫来完成;2.例1可以用一个简单的多行字符串来完成
与其用'cat'创建另一个进程,为什么不使用IFS='' read -r -d来代替?
值得注意的是,当使用 tee 而不是 cat 时, sudo 可以用来向一个受限位置的文件写入。例如,像 sudo tee /etc/somepath/file > /dev/null <<EOF ... 一样
我认为 cat 只适用于带有here-document的完整bash命令,如果没有 cat 或其他命令。以符号 << 开始的here-document不能回声到 stdout ,并且第一行的其余部分 "grep 'b' | tee b. txt "不能得到输入。txt "无法获得输入。
为什么这个答案有任何加分?你刚刚完全忽略了问题,即 "如何/为什么会这样"。没有人要求列出随机的例子,但不知为何,它比(正确)接受的答案有更多的支持率。
kennytm
kennytm
发布于 2018-08-14
0 人赞同

这被称为 heredoc 格式来提供一个字符串到stdin中。见 https://en.wikipedia.org/wiki/Here_document#Unix_shells 了解更多细节。

From man bash :

Here Documents

这种类型的重定向指示shell读取来自 的输入,直到有一行 含有单词(不含尾部的

所有读到这一点的行都被用作 作为一个命令的标准输入。

这里的文件格式是。

          <<[-]word
                  here-document
          delimiter
  

没有参数扩展、命令替换、算术扩展或 路径名扩展是在 word. 如果有任何字符在word是 引述的,是 delimiter是指在word,和线 中的here-document没有扩大。 如果word是未引用的,所有行的 here-document 要经过参数扩展、命令 替换,以及算术 扩充。 在后一种情况下, 字符序列\<newline>被忽略 忽略,而\必须用于引用字符\$`

如果重定向操作符是<<-,那么所有前面的制表符 将被从输入行中删除,并且包含 行中包含delimiter. 这样 允许 shell 脚本中的文件以一种自然的方式缩进。

我在禁用变量/参数扩展方面遇到了最困难的问题。我所需要做的就是使用 "双引号",这就解决了这个问题。谢谢你提供的信息!
关于 <<- 请注意,只有领先的 标签 characters are stripped -- not soft 标签 characters. This is one of those rare case when you actually need the 标签 character. If the rest of your document uses soft 标签s, make sure to show invisible characters and (e.g.) copy and paste a 标签 character. If you do it right, your syntax highlighting should correctly catch the ending delimiter.
我看不出这个答案比下面的答案有什么帮助。它只是转述了在其他地方可以找到的信息(很可能已经检查过了)。
@BrDaHa,也许不是。为什么会有这样的问题?"因为涨粉?"它 几年来唯一的一次。通过比较日期可以看出。
这篇摘录自手册的文章教会了我如何写出漂亮而又易于理解的文档。令人惊奇!
edelans
edelans
发布于 2018-08-14
0 人赞同

在你的例子中,"EOF "被称为 "此处标签"。基本上 <<Here 告诉shell你要输入一个多行字符串,直到 "标签" Here 。你可以随心所欲地命名这个标签,它通常是 EOF STOP

关于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.
  • $ 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
        
    这是最好的实际答案......你对两者都进行了定义,并清楚地说明了使用的主要目的,而不是相关的理论......这很重要,但没有必要......谢谢--超级有帮助
    @edelans 你必须补充说,当 <<- 被使用时,领先的tab不会阻止标签被识别。
    你的回答让我想到了 "你要输入一个多行字符串"
    Ciro Santilli OurBigBook.com
    Ciro Santilli OurBigBook.com
    发布于 2018-08-14
    0 人赞同

    POSIX 7

    kennytm引用了 man bash ,但其中大部分也是POSIX 7。 http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_07_04 :

    The redirection operators "<<" and "<<-" both allow redirection of lines contained in a shell input file, known as a "here-document", to the input of a command.

    这里的文件应被视为一个单字,在下一个 <newline> 之后开始,一直到有一行只包含分隔符和一个 <newline> ,中间没有 <blank> 字符。然后,如果有的话,就开始下一个here-document。其格式如下。

    [n]<<word
        here-document
    delimiter
    

    其中可选的n代表文件描述符的编号。如果数字被省略,这里的文件指的是标准输入(文件描述符0)。

    如果单词中的任何字符是带引号的,则应通过对单词进行去引号处理来形成定界符,并且此处的文件行不应被扩展。否则,定界符应是单词本身。

    如果单词中没有字符被加引号,这里的文件的所有行都应被展开,用于参数扩展、命令替换和算术扩展。在这种情况下,输入中的<backslash>的行为与双引号内的<backslash>一样(见双引号)。然而,双引号字符('"')在here-document中不应被特别处理,除非双引号出现在"$()"、"``"或"${}"中。

    If the redirection symbol is "<<-", all leading <tab> characters shall be stripped from input lines and the line containing the trailing delimiter. If more than one "<<" or "<<-" operator is specified on a line, the here-document associated with the first operator shall be supplied first by the application and shall be read first by the shell.

    当从终端设备上读取here-document,并且shell是交互式的,在读取每一行输入之前,它将把变量PS2的内容写到标准错误中,并按照Shell变量中的描述进行处理,直到分界符被识别。

    Examples

    有些例子还没有给出。

    Quotes prevent parameter expansion

    Without quotes:

    cat <<EOF

    Output:

    With quotes:

    cat <<'EOF'

    或(丑陋但有效)。

    cat <<E"O"F

    Outputs:

    Hyphen removes leading tabs

    Without hyphen:

    cat <<EOF
    <tab>a
    

    其中<tab>是一个字面标签,可以插入Ctrl + V <tab>

    Output:

    <tab>a
    

    With hyphen:

    cat <<-EOF
    <tab>a
    <tab>EOF
    

    Output:

    这当然是为了让你的cat能够像周围的代码一样缩进,这样更容易阅读和维护。例如。

    if true; then
        cat <<-EOF
    

    不幸的是,这对空格字符不起作用。POSIX倾向于在这里进行tab缩进。呀。

    在你讨论 <<- <tab>a 的最后一个例子中,应该注意到,其目的是允许在脚本中正常缩进代码,同时允许提交给接收进程的heredoc文本从第0列开始。这是一个不太常见的特征,多了解一些情况可能会避免很多挠头的事情......
    如果我的EOF标签之间的内容有些需要扩展,有些不需要,我应该如何逃避扩展?
    Jeanmichel Cote
    ...只需在 $ 前面使用反斜杠即可。
    @JeanmichelCote 我没有看到一个更好的选择 :-)对于普通字符串,你也可以考虑混合引号,如 "$a"'$b'"$c" ,但这里没有类似的东西,AFAIK。
    I have used <<- in my script but it does not ignores the leading tab characters.
    Andreas Maier
    Andreas Maier
    发布于 2018-08-14
    0 人赞同

    使用三通而不是猫

    不完全是对原问题的回答,但我还是想分享一下。我需要在一个需要root权限的目录下创建一个配置文件。

    下面的方法对这种情况不起作用。

    $ sudo cat <<EOF >/etc/somedir/foo.conf
    # my config file
    foo=bar
    

    因为重定向是在sudo环境之外处理的。

    我最后用这个代替。

    $ sudo tee <<EOF /etc/somedir/foo.conf >/dev/null
    # my config file
    foo=bar
        
    in your case use sudo bash -c 'cat <<EOF >/etc/somedir/foo.conf # my config file foo=bar EOF'
    Chris Halcrow
    Chris Halcrow
    发布于 2018-08-14
    0 人赞同

    替换代码0】基本上意味着。

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

    EoF - "在多行输入中发现 EoF 一词后立即停止阅读"

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

    Here Document经常被用来生成输出,以传递给后续进程。例如, cat << EoF 可以用来生成一个期望的输出,使用Here Document。

    下面是一个使用Here Document来即时创建文本文档的例子。

    cat << EoF > ./my-document.txt
    Hello world
    Have a nice day
        
    Lefty G Balogh
    Lefty G Balogh
    发布于 2018-08-14
    0 人赞同

    对上述答案做一个小小的延伸。尾部的 > 引导输入到文件中,覆盖现有内容。然而,一个特别方便的用法是双箭头 >> ,它可以追加,将你的新内容添加到文件的末尾,如:。

    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
    

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

    0 人赞同

    note to mention that cat << \EOT (see the backslash) will not expand any variables inside, while cat << EOT will do.

    FOO="bar"
    cat << \EOT > foobar.txt
    echo "$FOO"
    

    will output: echo $FOO

    while:

    FOO="bar"
    cat << EOT > foobar.txt
    echo "$FOO"
    echo "bar"

    yuranos
    yuranos
    发布于 2018-08-14
    0 人赞同

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

    $ cat >> temp.txt
    line 1
    line 2
    

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

    它是一个源代码文件的一个部分,被当作一个独立的文件来处理。 独立的文件。

    user9048395
    发布于 2018-08-14
    0 人赞同

    这不一定是对原问题的回答,而是分享我自己测试的一些结果。这个。

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

    将产生与以下相同的文件。

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

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

    哪个shell?我在Ubuntu 18.04上用bash 4.4测试,在OSX上用bash 3.2测试。当只使用 <<test 而不使用 cat <<test 时,两者都创建了一个空文件。
    Yordan Georgiev
    Yordan Georgiev
    发布于 2018-08-14
    0 人赞同

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