首页 > 解决方案 > 如果从 bash 脚本执行,则乱码邮件命令

问题描述

如果命令失败,我正在编写一个简单的 Bash 脚本来执行备份并在最后发送带有修改主题的邮件。

这是脚本的一个片段:

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}

邮件未发送,脚本退出并出现以下错误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

似乎 bash 在邮件命令的末尾“打乱”了参数。

我无法理解的是,如果我打印 $mail_cmd 它似乎是正确的:

mail -a "Content-Type: text/plain; charset=UTF-8" -s "Backup script" me@domain

我哪里错了?

标签: bashsendmail

解决方案


我相信你的脚本可以用一些 bash 数组来修复:

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[@]}"

但是重构脚本并创建一个函数会更好:

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[@]}"

笔记:

  • 通常使用 UPPER_CASE_VARIABLES 从脚本导出变量,而不是本地变量。
  • 您也可以导出函数。

我打印 $mail_cmd 是正确的

但是空间分离发生了,但"引用解释没有。我的意思是这条线:

mail -a "Content-Type: text/plain; charset=UTF-8" -s "Backup script" me@domain

被解释为(添加单引号):

mail -a '"Content-Type:' 'text/plain;' 'charset=UTF-8"' -s '"Backup' 'script"' me@domain

mail失败是因为前。text/plain不是有效的邮件地址。

mail_text="$output\n\n退出状态码:$status"

这里\n的不是换行符,而是字面上的\斜线和nn 字符。您可以使用简单的结构嵌入换行符,$'\n'例如:

 mail_text="$output"$'\n\n'"Exit status code: $status"

推荐阅读