135

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?

Benjamin W.
54k19 gold badges135 silver badges136 bronze badges
asked Sep 6, 2013 at 14:59
5
  • 13
    Is the EOF line indented? It has to be at the beginning of the line. Commented Sep 6, 2013 at 15:03
  • It is, but only as far as that entire statement is nested. So it has to be all the way to the left? Commented Sep 6, 2013 at 15:07
  • 2
    Also, ensure no trailing characters (including carriage return!) Commented Sep 6, 2013 at 15:07
  • 3
    If you indent with only tab characters, you can use <<-EOF -- gnu.org/software/bash/manual/bashref.html#Here-Documents Commented Sep 6, 2013 at 15:08
  • "when I run this " - what does that mean? Where does myfile.sh from the output come from? How is this problem even related to email? Commented Nov 6, 2024 at 12:34

9 Answers 9

229

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.

tripleee
192k37 gold badges319 silver badges370 bronze badges
answered Sep 6, 2013 at 15:10
Sign up to request clarification or add additional context in comments.

5 Comments

In the code example above, the EOF token is at the beginning of the line.
I don't see it in the edit history, but it must have been indented originally, because I wasn't the only one to point out this problem.
I get this error even when I remove all unnecessary whitespace.
Check for CR characters, and use dos2unix to fix it.
Hey Me! The space after EOF always gets me at my job (modifying scripts)... I'll be back here... See you again in a few months!
22

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.

answered Sep 6, 2013 at 15:07

Comments

10

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.

answered Sep 6, 2013 at 15:06

2 Comments

The first suggestion won't help (did you test to see whether space causes a problem?). The second will only help if the EOF line is indented with TAB, not spaces.
I think that the terminating token must not have leading spaces
4

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.

answered Jul 13, 2022 at 0:27

Comments

2

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.

answered Sep 4, 2019 at 13:21

Comments

1

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

tripleee
192k37 gold badges319 silver badges370 bronze badges
answered Jun 16, 2022 at 17:56

Comments

0

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:

  • auto-formats well for me in my IDE of choice (sublime)
  • is multi-line
  • can use spaces or tabs as indentation
  • preserves indentations within the comment.
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.

answered Sep 20, 2020 at 9:11

Comments

-1

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.

answered May 23, 2017 at 20:06

4 Comments

I find no support for this in either theory or practice. Downvoting as superstition.
I had a multiline here-doc wrapped in parens to redirect to cat and due to the formatting, right before my closing here-doc marker I needed to add an enter before the closing paren otherwise I'd get this mismatch. Upvoting as completely valid for "some" folks out there, albeit probably an unlikely scenario.
I hate to contribute to superstition, but I also was having this issue, and added a blank line after the end of my EOF. (ubuntu 19.10 running in docker; this was in a bootstrap.sh script). The blank line fixed this error.
This also fixed my issue when passing yaml files to GCP cloudbuild
-1

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:

  • if the content is expected to have simple quotes, either escape them using \ 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.
  • the given example print a trailing empty line, there are numerous way to get rid of it, not included here to keep the proposal to a minimum clutter
  • the flexibility comes from the ease with which you can control how much leading space should stay or go, provided that you know some sed REGEXP of course.
answered Apr 7, 2020 at 7:14

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.