Ugur
Ugur

Reputation: 2024

Bash - heredoc with variable expansion, preserving newlines

I am trying to generate the mail text for the send mail client ssmtp within a bash script (instead of putting it in a file).

Using heredocs I came up with this:

[email protected]
[email protected]
SUBJ="$HOSTNAME: Daemon not running"

read -d '' msg <<EOF
    To: $MAILTO
    From: $FROM
    Subject: $SUBJ

    Please check $HOSTNAME.
    Daemon has stopped running.

    -Admin
EOF

echo $msg | ssmtp $MAILTO

(This does not work. ssmtp does not send the mail, because the text does not preserve the newlines.)

If I echo $msg, then I see that the newlines in the heredoc are not preserved. How can I accomplish that?

Also: Where is the difference btw this

{
  echo "To: $MAILTO"
  echo "From: $FROM"
  echo "Subject: $SUBJ"
  echo
  echo "Please check $HOSTNAME"
} | ssmtp $MAILTO

and the first example? Are all echo commands executed and the result piped to ssmtp? Isn't this working in my first example? Can't I echo a text and pipe echo's output to a command?

Upvotes: 1

Views: 1623

Answers (2)

chepner
chepner

Reputation: 530960

First, you don't need read for this:

msg="\
To: $MAILTO
From: $FROM
Subject: $SUBJ

Please check $HOSTNAME.
Daemon has stopped running.

-Admin"

Second, you should always quote parameter expansions; you'll know when doing so isn't what you want, and such cases are rare.

echo "$msg" | ssmtp "$MAILTO"

Finally, consider whether you need msg in the first place:

ssmtp "$MAILTO" <<EOF
To: $MAILTO
From: $FROM
Subject: $SUBJ

Please check $HOSTNAME.
Daemon has stopped running.

-Admin
EOF

Upvotes: 4

0xplt
0xplt

Reputation: 191

Your second example uses Command Grouping. So your assumption, that all echo commands are executed and piped to ssmtp is correct.

From the manual:

Placing a list of commands between curly braces causes the list to be executed in the current shell context. No subshell is created.

Regarding your first example. This is not the heredoc's fault. Try to enclose msg in quotes:

echo "$msg" | ssmtp "$MAILTO"

Upvotes: 1

Related Questions