我在Windows上有一个包含CR和CRLF的文件。
我在上面运行了这个命令:
$ sed -i 's \x0d \x0a ' foo
我得到的是:
但是
为什么会这样?
答案 0 :(得分:2)
假设您在 Unix 平台上运行此操作,使用 GNU sed
:
sed -i 's/\r/\n/g; s/\n$//' foo
这将替换所有已隔离的CR(\r
,\x0d
)实例以及 one LF的CRLF(\r\n
,\x0d\x0a
)序列(\n
,\x0a
)每个 - 请参阅底部以获得解释。
至于您尝试的内容(同样,假设您在 Unix 平台上运行此操作,使用 GNU {{1} }):
sed
读取所有内容,但不包括LF(sed
)作为单行,并且在输出上,终止该行LF。
在您的情况下,这意味着单行读取将结束在CR(\n
)中(由于\r
读取到CRLF,剥离LF ),可能在该行中包含隔离的 CR实例。
sed
,由于未使用选项's \x0d \x0a '
,因此将最多1个 CR字符替换为。
应该导致:
每行的第一个 CR(g
,\r
)实例应该已替换为LF(\x0d
,{{1} })
当前行上的任何其他CR实例 - 包括一个属于行结束CRLF序列的CR实例 - 都将一个接一个。
\n
来电? \x0a
全局(s
)使用LF替换当前行中的所有 CR('s/\r/\n/g'
)实例g
。
因为作为行结束CRLF一部分的CR也被\r
替换,所以内容行(模式空间,在{{1}中现在以\n
结束。
因为\n
总是在输出上追加一个LF(sed
),所以必须删除额外的尾随\n
,这就是{{ 1}}确实。
答案 1 :(得分:1)
此行为的原因是unix中以\r
结尾的行显示为一行,下一行包含\n
:
$ echo -e "line1\rline2\r\nline3" |cat -A
line1^Mline2^M$
line3$
结果你的sed,没有g选项,将取代这个“连接”行中的第一个\ r \ n:
$ echo -e "line1\rline2\r\nline3" |sed 's \x0d \x0a ' |cat -A
line1$
line2^M$ #this is same input line as line1 and thus \r is not replaced the second time in the same line without g
line3$
如果在同一个被认为是输入行的内容中多次找到\r
,则需要包含g以进行全局替换:
$ echo -e "line1\rline2\r\nline3\rline4\r\nline5\r\nline6" |cat -A
line1^Mline2^M$ #line2 \r will not be replaced without g
line3^Mline4^M$ #line4 \r will not be replaced without g
line5^M$ # This \r will be replaced since it is unique on input line
line6$
$ echo -e "line1\rline2\r\nline3\rline4\r\nline5\r\nline6" |sed 's \r \n ' |cat -A
line1$
line2^M$
line3$
line4^M$
line5$ #the \r is removed from here even without g , since input line5 was alone
$
line6$
$ echo -e "line1\rline2\r\nline3\rline4\r\nline5\r\nline6" |sed 's \r \n g' |cat -A
line1$
line2$
$
line3$
line4$
$
line5$
$
line6$
注意:
从上述测试中可以明显看出,将\r
替换为\n
会使CRLF
成为LFLF
= \n\n
,这会产生额外的空白行。这可能是也可能不是所希望的。这个额外的行可以按照建议删除,即回答mklement0