【问题标题】:here-document gives 'unexpected end of file' errorhere-document 给出“文件意外结束”错误
【发布时间】:2013-09-10 17:34:38
【问题描述】:

我需要我的脚本从终端发送电子邮件。根据我在这里和网上许多其他地方看到的内容,我将其格式化为:

/var/mail -s "$SUBJECT" "$EMAIL" << EOF
Here's a line of my message!
And here's another line!
Last line of the message here!
EOF

但是,当我运行它时,我会收到以下警告:

myfile.sh: line x: warning: here-document at line y delimited by end-of-file (wanted 'EOF')

myfile.sh: line x+1: syntax error: unexpected end of file

...其中第 x 行是程序中最后写入的代码行,第 y 行是其中包含/var/mail 的行。我尝试用其他东西(ENDOFMESSAGEFINISH 等)替换 EOF,但无济于事。我在网上找到的几乎所有东西都是这样完成的,而且我对 bash 真的很陌生,所以我很难自己弄清楚。有人可以提供任何帮助吗?

【问题讨论】:

  • EOF 行是否缩进?它必须在行首。
  • 确实如此,但仅限于整个语句的嵌套。所以它必须一直向左?
  • 另外,确保没有尾随字符(包括回车!)
  • 如果你缩进只有个制表符,你可以使用&lt;&lt;-EOF -- gnu.org/software/bash/manual/bashref.html#Here-Documents

标签: bash email heredoc


【解决方案1】:

EOF 标记必须在行首,你不能将它与它的代码块一起缩进。

如果你写&lt;&lt;-EOF,你可以缩进它,但它必须缩进 Tab 字符,而不是空格。所以即使有代码块,它仍然可能不会结束。

还要确保在行上的EOF 标记之后没有空格。

【讨论】:

  • 在上面的代码示例中,EOF 标记位于行首。
  • 我在编辑历史中没有看到它,但它最初一定是缩进的,因为我不是唯一一个指出这个问题的人。
  • 即使我删除了所有不必要的空格,我也会收到此错误。
  • 检查CR字符,并使用dos2unix修复它。
【解决方案2】:

开始或结束 here-doc 的行可能有一些不可打印或空白字符(例如,回车),这意味着第二个“EOF”与第一个不匹配,并且不会结束 here -doc 应该如此。这是一个非常常见的错误,仅使用文本编辑器很难检测到。您可以使用 cat 使不可打印的字符可见:

cat -A myfile.sh

一旦您看到来自 cat -A 的输出,解决方案就会很明显:​​删除有问题的字符。

【讨论】:

    【解决方案3】:

    请尝试删除EOF:-之前的空格-

    /var/mail -s "$SUBJECT" "$EMAIL" <<-EOF
    

    使用&lt;tab&gt; 而不是&lt;spaces&gt; 进行标识并且使用

    "-" 删除了 &lt;tabs&gt;,而不是 &lt;spaces&gt;,但至少这是可行的。

    【讨论】:

    • 第一个建议没有帮助(您是否测试过空间是否会导致问题?)。第二个只有在 EOF 行使用 TAB 缩进时才有帮助,而不是空格。
    • 我认为终止标记不能有前导空格
    【解决方案4】:

    注意,如果你这样做,也会得到这个错误;

    while read line; do
      echo $line
    done << somefile
    

    因为在这种情况下&lt;&lt; somefile 应该是&lt; somefile

    【讨论】:

      【解决方案5】:

      这是一种处理多个缩进行不使用使用heredoc的灵活方法。

        echo 'Hello!'
        sed -e 's:^\s*::' < <(echo '
          Some indented text here.
          Some indented text here.
        ')
        if [[ true ]]; then
          sed -e 's:^\s\{4,4\}::' < <(echo '
            Some indented text here.
              Some extra indented text here.
            Some indented text here.
          ')
        fi
      

      关于此解决方案的一些说明:

      • 如果内容应包含单引号,请使用\ 对其进行转义或将字符串分隔符替换为双引号。在后一种情况下,请注意 $(command) 这样的构造将被解释。如果字符串同时包含单引号和双引号,则您至少必须转义。
      • 给定的示例打印一个尾随的空行,有很多方法可以摆脱它,这里不包括在内,以尽量减少提案的混乱
      • 灵活性来自于您可以轻松控制应该保留或离开多少前导空间,前提是您当然知道一些 sed REGEXP。

      【讨论】:

        【解决方案6】:

        当我想为我的 bash 函数使用 docstrings 时,我使用类似于 user12205 在此问题的 duplicate 中的建议的解决方案。

        查看我如何为解决方案定义 USAGE:

        • 在我选择的 IDE 中自动格式化非常适合我 (sublime)
        • 是多行的
        • 可以使用空格或制表符作为缩进
        • 在评论中保留缩进。
        function foo {
            # Docstring
            read -r -d '' USAGE <<'    END'
                # This method prints foo to the terminal.
                #
                # Enter `foo -h` to see the docstring.
                #      It has indentations and multiple lines.
                #
                # Change the delimiter if you need hashtag for some reason.
                # This can include $$ and = and eval, but won't be evaluated
            END
        
        
            if [ "$1" = "-h" ]
            then
                echo "$USAGE" | cut -d "#" -f 2 | cut -c 2-
                return
            fi
        
            echo "foo"
        }
        

        所以foo -h 产生:

        This method prints foo to the terminal.
        
        Enter `foo -h` to see the docstring.
             It has indentations and multiple lines.
        
        Change the delimiter if you need hashtag for some reason.
        This can include $$ and = and eval, but won't be evaluated
        

        说明

        cut -d "#" -f 2:检索# 分隔行的第二部分。 (想象一个以“#”为分隔符的 csv,第一列为空)。

        cut -c 2-: 检索结果字符串的倒数第二个字符

        另请注意,如果没有第一个参数,则if [ "$1" = "-h" ] 的计算结果为False,没有错误,因为它变成了一个空字符串。

        【讨论】:

          【解决方案7】:

          确保将结尾 EOF 放在新行的开头

          【讨论】:

            【解决方案8】:

            除了 Barmar 和 Joni 提到的其他答案外,我注意到在使用 &lt;&lt;-EOF 时,有时我必须在 EOF 前后留一个空行。

            【讨论】:

            • 无论是理论还是实践,我都找不到对此的支持。投反对票是迷信。
            • 我有一个用括号包裹的多行 here-doc 以重定向到 cat 并且由于格式的原因,在我关闭 here-doc 标记之前,我需要在结束括号之前添加一个输入,否则我会得到这种不匹配。投票对“某些”人来说是完全有效的,尽管这可能不太可能发生。
            • 我讨厌为迷信做出贡献,但我也遇到了这个问题,并在我的 EOF 结束后添加了一个空行。 (在 docker 中运行的 ubuntu 19.10;这是在 bootstrap.sh 脚本中)。空白行修正了这个错误。
            猜你喜欢
            • 2017-05-17
            • 2017-10-22
            • 2012-02-10
            • 2022-01-23
            • 2018-06-14
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多