我试图标准化一些文件,但没有成功,因为我似乎找不到与 SED 匹配的模式。在Notepad++中,我可以清楚地看到行尾的CRLF。
当查看不可打印的字符时,我得到一个^M与cat
和一个^M 或 \r在线的末尾。
在 Notepad++ 中我可以搜索\r\n\h+并删除回车符以及所有空格以将 CC: 连接起来,全部放在一行上,(有时可能会有几个换行符)
我想已经通过 SED Whiteout 成功尝试了所有组合。我还查看了此链接https://stackoverflow.com/questions/3569997/how-to-find-out-line-endings-in-a-text-file
我缺少什么?
尝试过但失败的例子
sed -En 's/\r\s+//g' $NewFile
sed -En 's/\r +//g' $NewFile
sed -En 's/\r\n +//g' $NewFile
sed -En 's/\n +//g' $NewFile
答案1
简单的修复方法是使用\r
在行尾搜索的正则表达式(在sed
读取文件时进行处理,但可以使用正则表达式锚点进行检测$
):
sed 's/\r$//' file.dos >file.txt
如果您sed
不支持文字\r
,请尝试使用 Bash“C 风格”字符串,该字符串在脚本中嵌入文字回车符sed
:
sed $'s/\r$//' file.dos >file.txt
...或使用 Awk,其中符号表示是标准的:
awk '{ sub(/\r$/, "") } 1' file.dos >file.txt
...或者使用该dos2unix
工具,该工具将逻辑封装到二进制文件中:
dos2unix file.dos
经过此预处理后,您可以使用标准电子邮件工具来提取标头。 Procmail 提供formail -c
(也可能添加-z
)折叠所有标题行,或者您可以使用简单的 Awk 单行。
awk '!body { if(NR > 1 && $0 ~ /^[^ \n]/) printf "\n"; printf "%s", $0 }
/^$/ { printf "\n"; body=1 }
body'
当然,如果您愿意,您可以将sub
早期 Awk 解决方案中的操作添加到该脚本的顶部。
答案2
sed 默认情况下一次只查看一行,甚至不包括缓冲区中的换行符,因此您不能执行类似的操作s/\r\n/.../
,更不用说s/\r\n +//
简单的方法了。您必须安排一次性处理整个文件。
我不确定这是否可以在 sed 中轻松完成,但至少对于 GNU sed,您可以使用该-z
选项让它使用 NUL 字节作为分隔符而不是换行符。文本文件不应该有 NUL,因此在实践中这会产生读入整个文件的效果。
例如,使用此输入文件:
$ cat -A foo.txt
from: foo bar^M$
to: someone ^M$
someone else^M$
cc: something ^M$
something else^M$
^M$
像这样的事情可能会起作用:
$ sed -z -Ee 's/\r\n +//g' foo.txt |cat -A
from: foo bar^M$
to: someone someone else^M$
cc: something something else^M$
^M$
或者你可以使用 Perl,它可以通过选项被告知读入整个文件-0777
。
$ perl -0777 -pe 's/\r\n +//g' foo.txt |cat -A
from: foo bar^M$
to: someone someone else^M$
cc: something something else^M$
^M$
不过,我不太确定电子邮件标头的处理规则是什么,所以我不会对此发表评论。但请注意,已有用于处理电子邮件的工具/库/模块。另外,如果您在同一个文件中包含消息数据,那么您在这里所做的操作也会破坏消息数据。
答案3
首先,感谢所有回复并引导我走向正确方向的人,如果我无法完成此任务,更不用说了解使用 SED 的过程了。我确实按照@seshoumara的建议尝试了 -z 选项和 dos2unix 实用程序,但由于某种原因我似乎无法让它工作。 @ilkkachu 也提供了丰富的信息。
因此,经过长时间彻底的搜索,我得出了以下结论。第一行提取电子邮件标题,直到找到空白,第二行将其标准化。
sed -n '0,/^\r/p' $f | tee bk/$NewFile
sed -Ei ':Loop ; $!N ; s/\n\s+/ / ; tLoop ; P ; D' bk/$NewFile
行结尾是最大的问题,何时使用 \r 或 \n 或 \r\n 并使用 dos2unix 解决了这个问题。我不确定为什么我能够使用第一个命令而不是第二个命令来使用 \r (我将其保存到以后)。