-1

我想使用 cron 作业,每三天一次将清理和排序邮件日志。

我的工作看起来像

 /bin/sed -i /status=/!d /var/log/maillog | 
    (/bin/grep "status=bounced" /var/log/maillog | /bin/grep -E -o --color "\b[a-zA-Z0-9.-]+@[a-zA-Z0-9.-]+\.[a-zA-Z0-9.-]+\b" | /bin/sort -u >> /root/unsent.log) | 
    (/bin/grep "status=deferred" /var/log/maillog | /bin/grep -E -o --color "\b[a-zA-Z0-9.-]+@[a-zA-Z0-9.-]+\.[a-zA-Z0-9.-]+\b" | /bin/sort -u >> /root/deferred.log) | 
    (/bin/grep "status=sent" /var/log/maillog | /bin/grep -E -o --color "\b[a-zA-Z0-9.-]+@[a-zA-Z0-9.-]+\.[a-zA-Z0-9.-]+\b" | /bin/sort -u >> /root/sent.log) | 
/bin/sed -i "/status=/d" /var/log/maillog

工作正常并执行 3 步:

  1. 从邮件日志中删除所有不包含“status=”的行
  2. 在不同的日志中对发送、退回、延迟进行排序。
  3. 从邮件日志中删除所有包含“状态”的行

完成这项工作后,我的邮件日志完全干净并分类为 3 个日志。

但是 Postfix 不想将下一条记录写入邮件日志。

我删除了 sed 命令,Postfix 可以很好地写入下一条记录。

为什么执行 cron 作业后 sed 命令会阻止邮件日志?

4

2 回答 2

1

sed -i将取消它修改的文件的链接,因此 syslog/postfix 将继续写入不存在的文件。

来自http://en.wikipedia.org/wiki/Sed

注意:“sed -i”用新文件覆盖原始文件,破坏原始文件可能具有的任何链接

更常见的做法是在使用类似logrotateor之类的工具将日志文件旋转到位后处理日志文件savelog,以便 syslog 可以不间断地继续写入。

如果您必须/var/log/maillog就地编辑,您可以在 cron 作业的末尾添加一行,以便在完成后重新加载 syslog。请注意,如果这样做,您可能会在脚本运行时丢失写入文件的日志行。该命令将取决于您正在运行的发行版/操作系统。在使用 rsyslog 的 ubuntu 上,它将是reload rsyslog >/dev/null 2>&1.

于 2012-04-05T10:33:20.457 回答
0

我已重新格式化您的原始代码以突出显示您添加的管道

 /bin/sed -i /status=/!d /var/log/maillog \
 | (/bin/grep "status=bounced" /var/log/maillog \
     | /bin/grep -E -o --color "\b[a-zA-Z0-9.-]+@[a-zA-Z0-9.-]+\.[a-zA-Z0-9.-]+\b" \
     | /bin/sort -u >> /root/unsent.log\
   ) \
 | (/bin/grep "status=deferred" /var/log/maillog \
   | /bin/grep -E -o --color "\b[a-zA-Z0-9.-]+@[a-zA-Z0-9.-]+\.[a-zA-Z0-9.-]+\b" \
   | /bin/sort -u >> /root/deferred.log\
   ) \
 | (/bin/grep "status=sent" /var/log/maillog \
   | /bin/grep -E -o --color "\b[a-zA-Z0-9.-]+@[a-zA-Z0-9.-]+\.[a-zA-Z0-9.-]+\b" \
   | /bin/sort -u >> /root/sent.log \
   ) \
 | /bin/sed -i "/status=/d" /var/log/maillog

sed -i正如@alberge 指出的那样,在同一个文件上进行所有这些处理时,您很可能会丢失日志消息。

我提出了一种不同的方法:

我会将邮件日志移动到一个过时的文件名,(这里的假设是 Postfix 将创建一个具有它“喜欢”使用的标准名称的新文件(/var/log/maillog)。

那么您的真正目标似乎是将各种类别的消息提取到单独命名的文件中,即 unsent.log、deferred.log、send.log 然后您将丢弃任何不包含该字符串的行status=(尽管您这样做了第一的)。

这是我的替代方案(请阅读整个消息,不要立即复制/粘贴/执行!)。

 logDate=$(/bin/date +%Y%m%d.%H%M%S)
 /bin/mv /var/log/maillog /var/log/maillog.${logDate}

 /bin/grep "status=bounced" /var/log/maillog.${logDate} \
 | /bin/grep -E -o --color "\b[a-zA-Z0-9.-]+@[a-zA-Z0-9.-]+\.[a-zA-Z0-9.-]+\b" \
 | /bin/sort -u \
 >> /root/unsent.log.${logDate} 

 /bin/grep "status=deferred" /var/log/maillog.${logDate} \
 | /bin/grep -E -o --color "\b[a-zA-Z0-9.-]+@[a-zA-Z0-9.-]+\.[a-zA-Z0-9.-]+\b" \
 | /bin/sort -u \
 >> /root/deferred.log.${logDate}

/bin/grep "status=sent" \
| /bin/grep -E -o --color "\b[a-zA-Z0-9.-]+@[a-zA-Z0-9.-]+\.[a-zA-Z0-9.-]+\b" \
| /bin/sort -u \
>> /root/sent.log.${logDate} 

要测试此代码是否正常工作,请将第二行 ( /bin/mv ....)替换为

  /bin/cp /var/log/maillog /var/log/maillog.${logDate}

将其复制/粘贴到终端窗口中,确认复制正确,然后复制/粘贴每个部分,一次 1 个,并检查每个日志文件/var/log/maillog.${logDate}中是否创建了预期的输出。/root

(如果您收到任何这些块的错误消息,请确保在每一行的最后一个 '\' 字符之后没有空格/制表符字符。或者您可以将这 3 个管道中的每一个折叠回一行,删除'\' 字符随你去。

(请注意,为了创建每个/root日志文件,我不使用任何通过被子进程包围的管道的连接部分。但是,在其他情况下,我确实使用这种技术来解决高级问题,所以不要扔技术离开,只在真正需要时使用它;-)!

在您确认所有这些都按您的需要工作后,您可以扩展脚本以进行最后的清理:

/bin/rm  /var/log/maillog.${logDate}

我已添加${logDate}到您的每个输出文件中,但正如我看到您正在使用的那样,sort -u >>您可能希望删除子日志文件名称(unsent.log、deferred.log、send.log)的“扩展名”,然后让这些文件自然增长。在任何一种情况下,您都必须在某个时候返回并确定您希望将这些数据保留多长时间,并制定计划和方法来在这些日志文件无用时如何清理它们。我想有人提到logrotate包。您可能希望将其视为您的长期解决方案。


该解决方案避免了创建大量额外进程,并且(大部分)消除了丢失日志记录的可能性。我认为如果 Postfix 在您移动文件的同一瞬间写入日志文件,您可能会丢失全部或部分记录。但是您的解决方案会有类似的问题,并且有更多的机会发生这种情况。

如果我误解了您的设计意图,使用嵌套( .... ) | ( .... )子流程,对不起!考虑更新您的帖子以包含您使用该技术的原因。

我希望这有帮助。

于 2012-04-06T04:52:04.897 回答