此处文档给出“意外的文件结尾”错误

问题描述 投票:0回答:9

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

/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
的行。我尝试用其他东西(
EOF
ENDOFMESSAGE
等)替换
FINISH
,但无济于事。我在网上找到的几乎所有内容都是这样完成的,而且我对 bash 真的很陌生,所以我很难自己弄清楚它。有人可以提供帮助吗?

bash email heredoc
9个回答
216
投票

EOF
标记必须位于行的开头,您不能将其与它所附带的代码块一起缩进。

如果您写

<<-EOF
,您可以缩进,但必须使用 Tab 字符缩进,而不是空格。所以即使有了代码块,它仍然可能不会结束。

还要确保该行的 EOF 标记

之后
没有空格。


22
投票

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

cat
:

cat -A myfile.sh

一旦看到

cat -A
的输出,解决方案就会显而易见:删除有问题的字符。


9
投票

请尝试删除前面的空格

EOF
:-

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

使用

<tab>
代替
<spaces>
进行识别并使用 <<-EOF works fine.

"-"
删除了
<tabs>
,而不是
<spaces>
,但至少这有效。


4
投票

对于任何在这里绊倒的人谷歌搜索“bash警告:此处文档由文件结尾分隔”,您可能会得到

警告:此处文档第 74 行由文件结尾分隔

...键入警告,因为 当您打算使用 here string 符号 (

<<
) 时,您不小心使用了 here document 符号 (
<<<
)。
这就是我的情况。


2
投票

注意,如果您这样做,也可能会出现此错误;

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

因为在这种情况下

<< somefile
应阅读
< somefile


1
投票

可能很旧,但在结尾 EOF 后有一个空格 << EOF blah blah EOF <-- this was the issue. Had it for years, finally looked it up here


0
投票

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

了解我如何定义解决方案的 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
,不会出现错误,因为它会变成空字符串。


-1
投票

除了 Barmar 和 Joni 提到的其他答案之外,我注意到在使用

<<-EOF
时有时必须在 EOF 前后留下空行。


-1
投票

这是一种灵活的方法来处理多个缩进行,无需使用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。
© www.soinside.com 2019 - 2024. All rights reserved.