Reputation: 3487
I need my script to send an email from terminal. Based on what I've seen here and many other places online, I formatted it like this:
/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
However, when I run this I get this warning:
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
...where line x is the last written line of code in the program, and line y is the line with /var/mail
in it. I've tried replacing EOF
with other things (ENDOFMESSAGE
, FINISH
, etc.) but to no avail. Nearly everything I've found online has it done this way, and I'm really new at bash so I'm having a hard time figuring it out on my own. Could anyone offer any help?
Upvotes: 134
Views: 209117
Reputation: 19
May be old but I had a space after the ending EOF
<do something here> << EOF
blah
blah
EOF<space>
this was the issue. Had it for years, finally looked it up here
Upvotes: 1
Reputation: 52489
For anyone stumbling here who googled "bash warning: here-document delimited by end-of-file", it may be that you are getting the
warning: here-document at line 74 delimited by end-of-file
...type warning because you accidentally used a here document symbol (<<
) when you meant to use a here string symbol (<<<
). That was my case.
Upvotes: 4
Reputation: 1
When I want to have docstrings for my bash functions, I use a solution similar to the suggestion of user12205 in a duplicate of this question.
See how I define USAGE for a solution that:
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"
}
So foo -h
yields:
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
Explanation
cut -d "#" -f 2
: Retrieve the second portion of the #
delimited lines. (Think a csv with "#" as the delimiter, empty first column).
cut -c 2-
: Retrieve the 2nd to end character of the resultant string
Also note that if [ "$1" = "-h" ]
evaluates as False
if there is no first argument, w/o error, since it becomes an empty string.
Upvotes: 0
Reputation: 3031
Here is a flexible way to do deal with multiple indented lines without using 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
Some notes on this solution:
\
or replace the string delimiters with double quotes. In the latter case, be careful that construction like $(command)
will be interpreted. If the string contains both simple and double quotes, you'll have to escape at least of kind.Upvotes: -1
Reputation: 2228
Note one can also get this error if you do this;
while read line; do
echo $line
done << somefile
Because << somefile
should read < somefile
in this case.
Upvotes: 2
Reputation: 780788
The EOF
token must be at the beginning of the line, you can't indent it along with the block of code it goes with.
If you write <<-EOF
you may indent it, but it must be indented with Tab characters, not spaces. So it still might not end up even with the block of code.
Also make sure you have no whitespace after the EOF
token on the line.
Upvotes: 226
Reputation: 29
Along with the other answers mentioned by Barmar and Joni, I've noticed that I sometimes have to leave a blank line before and after my EOF when using <<-EOF
.
Upvotes: -1
Reputation: 111219
The line that starts or ends the here-doc probably has some non-printable or whitespace characters (for example, carriage return) which means that the second "EOF" does not match the first, and doesn't end the here-doc like it should. This is a very common error, and difficult to detect with just a text editor. You can make non-printable characters visible for example with cat
:
cat -A myfile.sh
Once you see the output from cat -A
the solution will be obvious: remove the offending characters.
Upvotes: 22
Reputation: 172398
Please try to remove the preceeding spaces before EOF
:-
/var/mail -s "$SUBJECT" "$EMAIL" <<-EOF
Using <tab>
instead of <spaces>
for ident AND using <<-EOF works fine.
The "-"
removes the <tabs>
, not <spaces>
, but at least this works.
Upvotes: 10