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

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

评论

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

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

另外,请确保没有结尾字符(包括回车!)

如果仅缩进制表符,则可以使用<<-EOF-gnu.org/software/bash/manual/bashref.html#Here-Documents

#1 楼

EOF令牌必须在行的开头,您不能将其缩进,也不能随其附带的代码块一起缩进。

如果编写<<-EOF,则可以缩进,但必须缩进带有制表符,而不是空格。因此,即使有代码块,它也可能仍然无法结束。

还要确保在线上的EOF令牌后面没有空格。

评论


在上面的代码示例中,EOF令牌位于该行的开头。

–安德鲁·科斯特(Andrew Koster)
3月18日18:25

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

– Barmar
3月18日18:31

即使删除所有不必要的空格,我也会收到此错误。

–安德鲁·科斯特(Andrew Koster)
3月18日19:13

检查CR字符,并使用dos2unix对其进行修复。

– Barmar
3月18日19:15

#2 楼

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

cat -A myfile.sh


一旦看到cat -A的输出,解决方案将显而易见:删除有问题的字符。 />

#3 楼

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

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


使用<tab>代替<spaces>来标识,并使用<<-EOF可以正常工作。

"-"删除了<tabs>,而不是<spaces>,但至少可以正常工作。

评论


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

– Barmar
2013年9月6日15:07



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

–拉胡尔·特里帕蒂(Rahul Tripathi)
2013年9月6日15:08

#4 楼

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

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


因为在这种情况下<< somefile应该读为< 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函数使用文档字符串时,可以使用类似于user12205的建议的解决方案,重复该问题。
请参见如何为以下解决方案定义用法:

在我选择的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 [ "" = "-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为分隔符,第一列为空)。 ,没有错误,因为它变为空字符串。

#7 楼

连同Barmar和Joni提到的其他答案,我注意到在使用<<-EOF时,有时我在EOF前后必须留空白行。

评论


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

–tripleee
17年11月27日在4:37

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

– SidOfc
19年11月16日在11:53

我不愿为迷信做贡献,但我也遇到了这个问题,在我的EOF结束后添加了一个空白行。 (ubuntu 19.10在docker中运行;这在bootstrap.sh脚本中)。空白行修复了此错误。

– NDP
1月16日23:51