我有一个巨大的邮箱,我想根据其内容的时间来管理:备份、存档或删除。我想按照这些邮箱所包含邮件的日期拆分这些邮箱。
对于邮箱:
${MAILDIR}/${TOPIC}
这是我想要跨越的新目录结构的方案:
${MAILDIR}/${YEAR}/${MONTH}/${TOPIC}
有没有办法在没有太多分叉命令的情况下实现这种拆分?
答案1
首先,需要澄清一些问题。标Date:
头不太可靠,因为发送者可以将其设置为几乎任何内容。然而,其他选择也不是很有吸引力。一些邮件客户端实际上尝试解析Received:
标头,但由于标头的内容未正确标准化,因此可能会失败。如果您的消息采用 Berkeley mbox 格式,则From_
伪标头通常包含本地传递时间戳,但我想有些传递程序也忽略了这一点(而且看起来您无论如何都没有使用 mbox)。
那么,让我们看看如何在Date:
不分叉的情况下解析 RFC822 标头。
另一个难题是并非所有发件人都在此标头中使用有效的 RFC822 日期。假设您没有对垃圾邮件进行分类,您可能可以为执行此操作的通讯员确定替代模式;我会简单地忽略这里的那堆蠕虫。 (我只是在处理垃圾邮件时遇到了这一点,但它似乎在来自日本的电子邮件中相当普遍,IIRC。)
我发现您并不关心月份中的哪一天,但我也将其包含在这里,以防其他人发现这很有用。
# Poor man's associative array... Remove leading zeros if desired
# (but then also change the MONTH regex below, as per comment there)
MONTHS='Jan 01
Feb 02
Mar 03
Apr 04
May 05
Jun 06
Jul 07
Aug 08
Sep 09
Oct 10
Nov 11
Dec 12'
:0
* ^Date:[ ]*[A-Z][a-z][a-z], \/[ 0-3][0-9] [A-Z][a-z][a-z] [12][0-9][0-9][0-9]
{
RDATE=$MATCH
:0
* RDATE ?? ^ *\/[1-9][0-9]?
{ DAY=$MATCH }
:0
* RDATE ?? () \/[12][0-9][0-9][0-9]
{ YEAR=$MATCH }
:0
* RDATE ?? () \/[A-Z][a-z][a-z]
{ MON=$MATCH }
:0 # Adjust if you don't want leading zeros -- $MON \/[1-9][0-9]?
* $ MONTHS ?? $MON \/[01][0-9]
{ MONTH=$MATCH }
:0 # Assume TOPIC is set by caller, or somehow determined above
$YEAR/$MONTH/$TOPIC
}
只是回顾一下上面使用的构造,\/
特殊标记会导致在其之后捕获任何匹配项MATCH
(Procmail 没有正确的反向引用),并且作为条件的前缀会VAR ??
导致条件应用于变量的值VAR
针对消息的标头。最后,$
如果您希望条件包含变量的扩展值(通常$
仅表示换行符),则需要使用它。哦,和往常一样, 中的空白[ ]*
应该是制表符和空格。
上面的配方主要用于解析单个消息。如果您想按日期拆分邮箱,我真的不明白如何避免单独解析每条消息,然后将其归档到所属的位置。
如果您确实想压缩优化,并在有限的时间内获得消息,我想您可以枚举您想要涵盖的每个月份的正则表达式,例如
for month in 2014/11 2014/12 2015/01 2015/02 2015/03; do
printf ':0\n* ^Date:[ \t]*[A-Z][a-z][a-z], [ 0-3][0-9] %s\n%s/$TOPIC\n' \
"$(date -d "${month%/*}-${month#*/}-01" +'%b %Y')" "$month"
done >months.rc
但我并不完全相信它实际上会节省您的任何周期(如果必须的话请衡量!:-)
答案2
为了完成此任务,我使用了 shell 脚本和 procmailrc 文件。
shell脚本的核心只是一种分割巨大邮箱并使用调整后的procmailrc文件将其提供给procmail的方法:
$ cat <<eof >splitter.sh
#!/bin/sh
orig_mailbox=$1
formail -s <${orig_mailbox} procmail ${HOME}/src/splitter_procmailrc
eof
procmailrc 文件基于单个规则,该规则将用于date
从标头中提取正确的字段Date:
(希望是系统在干净的操作系统上生成的字段)。date
还将输出YYYY/MM
格式为 的必填字段"+%Y/%m"
。
cat <<eof >${HOME}/src/splitter_procmailrc
MAILDIR=${HOME}/Mail/tmp
LOGFILE=${HOME}/Mail/tmp/procmail.log
:0 w
* ^Subject: TOPIC
* ^Date: \/.*$
| ( ;\
ORIG_MONTH_DIR=`date -j -f "%a, %d %b %Y" "${MATCH}" "+%Y/%m"` ;\
[ -d ${ORIG_MONTH_DIR} ] || mkdir -p ${ORIG_MONTH_DIR} ;\
cat >>${ORIG_MONTH_DIR}/TOPIC ;\
)
:0 E
Error
eof
第二条规则在这里是为了防止我在第一条规则上发现任何错误,以便能够对问题进行排序并调整 procmailrc 文件。