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


81

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

/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其他的事情(ENDOFMESSAGEFINISH,等),但无济于事。我在网上找到的几乎所有东西都是通过这种方式完成的,而且我对bash真的很陌生,所以我很难自己搞清楚。有人可以提供任何帮助吗?


9
EOF线是否缩进?它必须在该行的开头。
Barmar 2013年

可以,但是仅在整个语句嵌套的范围内。所以必须一直到左边吗?
thnkwthprtls 2013年

2
另外,请确保没有尾随字符(包括回车!)
glenn jackman 2013年

2
如果您有缩进制表符,你可以使用<<-EOF- gnu.org/software/bash/manual/bashref.html#Here-Documents
格伦·杰克曼

Answers:


153

EOF令牌必须是在该行的开头,您不能使用的代码它会与块一起缩进它。

如果您写的<<-EOF话可以缩进,但是必须缩进以Tab字符而不是空格。因此,即使使用代码块,它也可能仍未结束。

另外,还要确保你有没有空格EOF标记就行了。


2
在上面的代码示例中,EOF令牌位于该行的开头。
安德鲁·科斯特

我在编辑历史记录中没有看到它,但是它一定是最初缩进的,因为我不是唯一指出这一问题的人。
Barmar

即使删除所有不必要的空格,我也会收到此错误。
安德鲁·科斯特

检查CR字符,并使用dos2unix它进行修复。
Barmar

17

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

cat -A myfile.sh

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


7

请在EOF:-之前删除前面的空格:

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

使用<tab>代替<spaces>ident并使用<<-EOF可以正常工作。

"-"删除<tabs>,不是<spaces>,但至少这个作品。


2
第一个建议无济于事(您是否进行了测试以查看空间是否会引起问题?)。仅当EOF行用TAB而不是空格缩进时,第二个才有用。
Barmar 2013年

我认为终止令牌不能有前导空格
Rahul Tripathi

2

注意,如果执行此操作,也会出现此错误。

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

因为在这种情况下<< somefile应该阅读< somefile


0

这是一种无需使用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。

0

当我想为我的bash函数使用文档字符串时,我在此问题的副本中使用类似于user12205的建议的解决方案。

请参阅我如何定义USAGE的解决方案:

  • 在我选择的IDE中很好地自动格式化(崇高)
  • 是多行
  • 可以使用空格或制表符作为缩进
  • 保留注释中的缩进。
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前后留一个空白行<<-EOF


1
我在理论或实践中都找不到对此的支持。令人讨厌的投票。
人间

1
我有一个多行here-doc文件,该文件被包裹在parens中以重定向到cat该格式,并且由于格式问题,在我关闭here-doc标记之前,我需要在结束paren之前添加一个enter,否则我会得到这个不匹配的信息。尽管对于“某些”人来说,投票完全有效,但情况可能不太可能。
SidOfc

我不愿为迷信做贡献,但我也遇到了这个问题,在我的EOF结束后添加了一个空白行。(ubuntu 19.10在docker中运行;这在bootstrap.sh脚本中)。空白行修复了此错误。
NDP
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.