Reputation: 596
I'm writing a simple Bash script to execute a backup and send a mail at the end with a modified subject if the command has been failed.
This is a snippet of the script:
BACKUP_CMD="ls -1" # Just an example command
MAIL_RECIPIENTS="me@domain" # Recipient addresses (space separated list)
MAIL_SUBJECT="Backup script" # Mail subject
MAIL_FAIL_SUBJECT_PREPEND="[!!! ---FAILURE--- !!!] "
MAIL_CMD="mail -a \"Content-Type: text/plain; charset=UTF-8\" -s \"SUBJECT\" RECIPIENTS" # Mail send command
# Execute backup
output="$($BACKUP_CMD)"
status=$?
# Check exit status code and compose the mail message
echo $status
if [ "$status" -eq "0" ]; then
mail_subject=$MAIL_SUBJECT
mail_text="${output}"
else
mail_subject="$MAIL_FAIL_SUBJECT_PREPEND $MAIL_SUBJECT"
mail_text="$output\n\nExit status code: $status"
fi
# Compose the mail command with subject and recipients list
mail_cmd=$MAIL_CMD
mail_cmd="${mail_cmd/SUBJECT/$mail_subject}"
mail_cmd="${mail_cmd/RECIPIENTS/$MAIL_RECIPIENTS}"
echo "$mail_text" | ${mail_cmd}
The mail is not sent and the script exits with this error from send-mail
:
send-mail: RCPT TO:<Backup", charset=UTF-8"@server.domain> (501 5.1.3 Bad recipient address syntax)
Can't send mail: sendmail process failed with error code 1
It seems that bash "scrambles" arguments at the end of the mail command.
What I cannot understand is that if I print $mail_cmd it seems to be correct:
mail -a "Content-Type: text/plain; charset=UTF-8" -s "Backup script" me@domain
Where I'm wrong?
Upvotes: 0
Views: 91
Reputation: 140880
Your script could be fixed with some bash arrays I believe:
backup_cmd=(ls -1)
mail_cmd2=(mail -a "Content-Type: text/plain; charset=UTF-8" -s)
...
output=$("${backup_cmd[@]}")
...
mail_cmd=("${mail_cmd2[@]}")
mail_cmd+=("$mail_subject")
mail_cmd+=( $MAIL_RECIPIENTS )
# MAIL_RECIPIENTS should be changed to a bash array too!
echo "$mail_text" | "${mail_cmd[@]}"
But would be way better to refactor the script and create a function:
mail_cmd() {
local subject recipients
subject="$1"
shift
recipients=("$@")
mail -a "Content-Type: text/plain; charset=UTF-8" -s "$subjsect" "${recipients[@]}"
}
mail_recipients=( "me@domain" "other@otherdomain" )
...
printf "%s\n" "$mail_text" | mail_cmd "$subject" "${mail_recipients[@]}"
Notes:
I print $mail_cmd it is correct
But the space separation happens, but the "
quote interpretation does not. What I mean is that the line:
mail -a "Content-Type: text/plain; charset=UTF-8" -s "Backup script" me@domain
is interpreted as (added single quotes):
mail -a '"Content-Type:' 'text/plain;' 'charset=UTF-8"' -s '"Backup' 'script"' me@domain
and mail
fails because ex. text/plain
is not a valid mail address.
mail_text="$output\n\nExit status code: $status"
The \n
are not newlines here, but literally \
slash and n
n character. You can embed a newline with simple $'\n'
construct like:
mail_text="$output"$'\n\n'"Exit status code: $status"
Upvotes: 1