行尾字符

行尾字符

我试图标准化一些文件,但没有成功,因为我似乎找不到与 SED 匹配的模式。在Notepad++中,我可以清楚地看到行尾的CRLF。

示例文本

当查看不可打印的字符时,我得到一个^Mcat和一个^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

也可以看看https://stackoverflow.com/questions/39527571/are-shell-scripts-sensitive-to-encoding-and-line-endings

经过此预处理后,您可以使用标准电子邮件工具来提取标头。 Procmail 提供formail -c(也可能添加-z)折叠所有标题行,或者您可以使用简单的 Awk 单行。

awk '!body { if(NR > 1 && $0 ~ /^[^ \n]/) printf "\n"; printf "%s", $0 }
  /^$/ { printf "\n"; body=1 }
  body'

当然,如果您愿意,您可以将sub早期 Awk 解决方案中的操作添加到该脚本的顶部。

演示:https://ideone.com/1z8uOU

答案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 (我将其保存到以后)。

相关内容