如果有输出,如何将此命令重写为仅发送电子邮件mailq | grep
?
mailq | egrep 'rejected|refused' -A 5 -B 5 | mail -s 'dd' email@email
这甚至可以在一条线上实现吗?
看检查管道是否为空,如果不是则对数据运行命令对于比发送电子邮件更一般的情况。
答案1
我认为您必须使用临时文件来执行此操作,以便您可以使用运算&&
符仅在 grep 返回退出状态表明它具有如下匹配项时运行邮件命令:
TMPFILE=`mktemp /tmp/mailqgrep.XXXXXX`; mailq | egrep 'rejected|refused' -A5 -B5 > "$TMPFILE" && mail -s 'dd' email@email < "$TMPFILE"; rm "$TMPFILE"
如果您不介意临时文件保留在某处并且可以为其使用静态名称,则可以跳过特殊的命名和删除内容:
mailq | egrep 'rejected|refused' -A5 -B5 > /tmp/mailqgrep && mail -s 'dd' email@email < /tmp/mailqgrep
编辑:看到后格伦的回答我又玩了一些,显然使用$()
语法分配一个变量会返回命令的退出代码,因此您可以跳过他用于字符串长度的测试并使用它。这一切都在一个命令中:
data=$(mailq | egrep 'rejected|refused' -A 5 -B 5) && mail -s 'dd' email@email <<< "$data"
编辑2:看到后西蒙的回答我检查了我的mail
程序。它的行为方式与他所描述的默认方式不同,但确实有一个选项。从手册页:
-E
如果传出消息的第一个或唯一的消息部分不包含任何文本,则不发送它,而是静默丢弃它,从而在程序启动时有效地设置skipemptybody变量。这对于从 cron(8) 启动的脚本发送消息非常有用。
使这成为可能:
mailq | egrep 'rejected|refused' -A 5 -B 5 | mail -E -s 'dd' email@email
答案2
实用程序伊夫内明确出于此目的而存在:如果标准输入不为空,则运行命令。
mailq | egrep 'rejected|refused' -A 5 -B 5 | ifne mail -s 'dd' email@email
ifne 命令是更多实用程序包,被宣传为“一个不断增长的 Unix 工具集合,很久以前,当 Unix 还很年轻的时候,没有人想到要编写这些工具”。
答案3
您可以将输出保存在变量中,然后在字符串长度非零时调用 mail 命令。
data=$(mailq | egrep 'rejected|refused' -A 5 -B 5)
[[ -n "$data" ]] && mail -s 'dd' email@email <<< "$data"
对于一行,用分号连接两个命令。
答案4
在这种特殊情况下,如果您mail
支持该-E
选项,就用它吧。一般情况下,可以尝试读一个字;如果有,则启动后处理命令并从文件的其余部分向其提供该字符。
pipe_if_not_empty () {
a=$(dd bs=1 count=1 2>/dev/null; echo .) # read at most one character
if [ "$a" != "." ]; then # if there were two characters,
{ printf %s "${a%.}"; # then output the first character
cat; } | # and the rest of the input
"$@" # into the specified program
fi
}
mailq | egrep 'rejected|refused' -A 5 -B 5 |
pipe_if_not_empty mail -s 'dd' email@email
注意 的有用用法cat
。添加echo .
使得即使输入中的第一个字符是换行符也可以使该函数起作用(请记住该$(…)
构造会去除终端换行符)。
对于大多数 shell(据我所知,除了 zsh 之外的任何 shell),如果文件以空字符开头,则此代码将认为它是空的。解决这个问题留给读者作为练习。 (提示:od
在第一个子 shell 中使用并printf
打印第一个字节。)(解决方案:如何检查管道是否为空) 如果文件以在当前语言环境中不是有效字符的字节开头,您可能会遇到相同的问题;通过使用 运行此代码更容易修复此问题LC_ALL=C
。