如果同一个文件中存在 CR 和 LF,sed 无法区分它们
sed can't differentiate CR from LF if both exist in the same file
我有一个文件,其中 CR (\r) 和 LF (\n) 存在于同一个文件中。
a1 a2 CRLF
b1 LF
b2 CRLF
c1 c2 CRLF
文件需要固定为:
a1 a2 CRLF
b1 b2 CRLF
c1 c2 CRLF
逻辑很简单:删除前面没有空字符串的 CR 的 LF:
sed 's/[^\r]\n//g' input.txt > output.txt
然而,这是行不通的!
我不得不删除所有出现的 LF,并将所有剩余的 CR 替换为 CRLF:
cat input.txt | tr -d '\n' | sed 's/\r/\r\n/g' >output.txt
这让我很烦。为什么 sed 不工作??
sed
在其操作的行中看不到行结尾。
这与 sed 's/\n//'
不给您只有一行的文件的原因相同。
处理换行符 "internally"。
这是 dos2unix
/unix2dos
/等需要完成的任务。可以更直接的为您办理。
@Etan Reisner 基本上是正确的 - sed 将文本处理为换行符分隔的行,因此您需要跳过一些步骤才能使其直接处理换行符。仅仅因为你可以做到这一点并不意味着它是最干净的方法,但如果你没有其他工具可供使用,这里有一个如何做到这一点的例子:
sed -e 's/[^\r]$/&/' -e te -e b -e :e -e N -e 's/\n//'
这个命令的作用是:
s/[^\r]$/&/
- 将一行末尾的 CR 替换为 ... 本身。
te
- 测试和分支:如果先前的替换成功,则分支到指示的标签。 (我们需要它才能成功,这就是为什么它用自己代替)
b
- 无条件跳转到脚本末尾
:e
- 为之前的 te
命令创建一个标签以跳转到
N
- 将下一行追加到模式 space 中。这会产生一个带有嵌入换行符的模式 space。
s/\n//
- 删除嵌入的换行符。
我会使用 awk
:
awk -v RS='\r\n' 'BEGIN { ORS = RS } { gsub(/\n/, ""); print }'
将记录分隔符 RS
设置为 \r\n
,文件将被拆分为由 \r\n
分隔的记录,因此删除这些记录中的换行符会删除所有换行符前面没有 \r
。将 ORS
(输出记录分隔符)设置为 RS
使得输出文件仍然具有 CRLF 行结尾。
请注意,多字符 RS
并不严格符合 POSIX。不过,最常见的 awk 支持它。
或者有 Perl 方式:
perl -pe 's/(?<!\r)\n//'
这依赖于消极的回顾; (?<!\r)
匹配前面没有 \r
的空字符串。请注意,与 sed 不同,没有 -l
的 Perl 不会从输入中删除换行符,因此不需要特殊技巧来删除它们。
我有一个文件,其中 CR (\r) 和 LF (\n) 存在于同一个文件中。
a1 a2 CRLF
b1 LF
b2 CRLF
c1 c2 CRLF
文件需要固定为:
a1 a2 CRLF
b1 b2 CRLF
c1 c2 CRLF
逻辑很简单:删除前面没有空字符串的 CR 的 LF:
sed 's/[^\r]\n//g' input.txt > output.txt
然而,这是行不通的!
我不得不删除所有出现的 LF,并将所有剩余的 CR 替换为 CRLF:
cat input.txt | tr -d '\n' | sed 's/\r/\r\n/g' >output.txt
这让我很烦。为什么 sed 不工作??
sed
在其操作的行中看不到行结尾。
这与 sed 's/\n//'
不给您只有一行的文件的原因相同。
处理换行符 "internally"。
这是 dos2unix
/unix2dos
/等需要完成的任务。可以更直接的为您办理。
@Etan Reisner 基本上是正确的 - sed 将文本处理为换行符分隔的行,因此您需要跳过一些步骤才能使其直接处理换行符。仅仅因为你可以做到这一点并不意味着它是最干净的方法,但如果你没有其他工具可供使用,这里有一个如何做到这一点的例子:
sed -e 's/[^\r]$/&/' -e te -e b -e :e -e N -e 's/\n//'
这个命令的作用是:
s/[^\r]$/&/
- 将一行末尾的 CR 替换为 ... 本身。te
- 测试和分支:如果先前的替换成功,则分支到指示的标签。 (我们需要它才能成功,这就是为什么它用自己代替)b
- 无条件跳转到脚本末尾:e
- 为之前的te
命令创建一个标签以跳转到N
- 将下一行追加到模式 space 中。这会产生一个带有嵌入换行符的模式 space。s/\n//
- 删除嵌入的换行符。
我会使用 awk
:
awk -v RS='\r\n' 'BEGIN { ORS = RS } { gsub(/\n/, ""); print }'
将记录分隔符 RS
设置为 \r\n
,文件将被拆分为由 \r\n
分隔的记录,因此删除这些记录中的换行符会删除所有换行符前面没有 \r
。将 ORS
(输出记录分隔符)设置为 RS
使得输出文件仍然具有 CRLF 行结尾。
请注意,多字符 RS
并不严格符合 POSIX。不过,最常见的 awk 支持它。
或者有 Perl 方式:
perl -pe 's/(?<!\r)\n//'
这依赖于消极的回顾; (?<!\r)
匹配前面没有 \r
的空字符串。请注意,与 sed 不同,没有 -l
的 Perl 不会从输入中删除换行符,因此不需要特殊技巧来删除它们。