/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真的很陌生,所以我很难自己搞清楚。有人可以提供任何帮助吗?#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
评论
EOF线是否缩进?它必须在该行的开头。可以,但是仅在整个语句嵌套的范围内。所以必须一直到左边吗?
另外,请确保没有结尾字符(包括回车!)
如果仅缩进制表符,则可以使用<<-EOF-gnu.org/software/bash/manual/bashref.html#Here-Documents