【问题标题】:Fixing corrupt mbox files with sed/awk使用 sed/awk 修复损坏的 mbox 文件
【发布时间】:2020-12-29 05:54:15
【问题描述】:

我有一堆旧的、继承的 mbox 文件,我想将它们转换为 maildir。 问题:mbox 不完全符合 RFC。 在某些(但不是全部)邮件中,有几个邮箱在“^From”行之前缺少空行,这导致 mb2md 无法将这些邮件彼此分开。

例子:

...
Text of mail 1
... bla....    
To unsubscribe, visit https:...                      
From fetchmail Fri Nov  8 18:35:54 CET 2002          ## ^missing empty line above
...
Text of mail 2
...

现在我正在寻找一种简单的方法,可以在任何匹配“^From”的行之前插入一个空行——但前提是前面没有空行。必须进行一种流式编辑,因为邮箱可能真的很大。

我经常使用 sed - 但我不熟悉多行匹配。今天尝试了几件事(修改后的剪切)没有成功:(

最后一次尝试是 sed -E ':a;N;$!ba;s/\n(..*)\nFrom /\n\1\n\nFrom /g' /tmp/testfile

只匹配最后一次出现的模式!?

sed/awk-experts - 你有什么提示吗?

【问题讨论】:

标签: awk sed multiline mbox


【解决方案1】:

只匹配最后一次出现的模式!?

是的。正则表达式是贪婪的.* 匹配所有内容,然后在匹配所有内容后,匹配最后一个\nFrom。匹配除换行符以外的所有内容,以匹配一行。

sed -z -E 's/(\n[^\n]+\n)(From )/\1\n\2/g'

如果您不想将整个文件读入内存,则必须至少读取内存中的两行。下面我将前一行放入保存空间 - 在读取的每一行上附加当前行和前一行以检查条件。检查后,打印上一行。

sed -n -E '
      # Hold first line.
      1{h;b}
      # Append the line to hold space and switch hold space with pattern space
      # so that we have previous\ncurrent lines in pattern space.
      H;x
      # If we have From prepended by anything in previous line, add a newline
      /.+\nFrom /s/\n/\n\n/
      # Remove current line
      s/\n[^\n]*$//
      # Print previous line. Maybe with extra newline.
      p
      # If its last line, also print the holded last line
      ${x;p}
'

和一个单线:

sed -nE '1{h;b};H;x;/.+\nFrom /s/\n/\n\n/;s/\n[^\n]*$//p;${x;p}'

【讨论】:

  • 这需要将整个文件读入内存,并且 OP 说文件 could be really huge。就个人而言,我什至不会考虑使用 sed 来完成这样的工作。
  • 了解:a;N;$!ba 的作用。召唤克苏鲁?不那么滑稽 - 我假设它在某种保持/缓冲的事情中连接输入行,但我不知道它是一次占用 2 行还是一次读取整个文件或其他什么,我也不知道是否它是 POSIX 或 GNU-only 或其他。据我所知,只是一堆神秘的符文,但我只使用 sed 大约 40 年 :-)。
【解决方案2】:

任何时候你使用sed 结构而不是 s、g 和 p(带 -n)时,你都在使用错误的工具。如果由于某种原因您不能使用formail,那么只需使用awk

$ awk '/^From/ && p{print ""} {p=NF; print}' file
...
Text of mail 1
... bla....
To unsubscribe, visit https:...

From fetchmail Fri Nov  8 18:35:54 CET 2002          ## ^missing empty line above
...
Text of mail 2
...

这将在任何 UNIX 机器上使用任何 awk 工作,它一次只读取 1 行,因此无论您的输入文件有多大,它都可以工作。

【讨论】:

  • 我认为您应该在/^From / 处留一个空格,因为在邮件中通常会有以From: 开头的行。
  • 是的,这种方法非常脆弱。 formail 是要走的路。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-03-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-10-13
  • 1970-01-01
相关资源
最近更新 更多