我需要我的脚本从终端发送电子邮件。基于我在这里和在线的许多其他地方所看到的,我将其格式化为:
/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上真的很新,所以我很难自己搞清楚。有人可以提供任何帮助吗?
答案 0 :(得分:114)
EOF
令牌必须位于该行的开头,您不能将其与随附的代码块一起缩进。
如果你写<<-EOF
,你可以缩进它,但它必须用 Tab 字符缩进,而不是空格。因此,即使使用代码块,它仍然可能不会结束。
此外,请确保在后面的EOF
令牌上没有空白。
答案 1 :(得分:10)
启动或结束here-doc的行可能有一些不可打印或空格的字符(例如回车),这意味着第二个“EOF”与第一个不匹配,并且不会在此结束-doc喜欢它应该。这是一个非常常见的错误,仅使用文本编辑器很难检测到。您可以使用cat
:
cat -A myfile.sh
一旦看到cat -A
的输出,解决方案将很明显:删除有问题的字符。
答案 2 :(得分:5)
请尝试删除EOF
之前的前一个空格: -
/var/mail -s "$SUBJECT" "$EMAIL" <<-EOF
使用<tab>
代替<spaces>
进行身份识别并使用&lt;&lt; -EOF可以正常工作。
"-"
删除<tabs>
,而不删除<spaces>
,但至少会有效。
答案 3 :(得分:1)
请注意,如果执行此操作,也会出现此错误;
while read line; do
echo $line
done << somefile
因为在这种情况下<< somefile
应该读为< somefile
。
答案 4 :(得分: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)
的构造。如果字符串同时包含单引号和双引号,则必须至少转义此类。答案 5 :(得分:0)
当我想为bash函数提供 docstrings 时,我使用的解决方案类似于该问题的user12205中对duplicate的建议。
看看我如何定义用于以下解决方案的用法:
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
,因为它成为空字符串。
答案 6 :(得分:0)
确保将结尾的 EOF 放在新行的开头
答案 7 :(得分:-3)
除了Barmar和Joni提到的其他答案之外,我注意到在使用<<-EOF
时,我有时必须在EOF之前和之后留下空白。