简体   繁体   中英

Scrambled mail command if executed from bash script

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?

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:

  • It is common to use UPPER_CASE_VARIABLES for exported variables from your script, not local.
  • You can export functions too.

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"

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM