如何用sed删除双换行符?

时间:2014-12-16 17:29:13

标签: linux bash sed

我试过了:

sed -i 's/\n+/\n/' file

但它不起作用。

我仍然想要单线换行。

输入:

abc

def


ghi




jkl

期望的输出:

abc

def

ghi

jkl

7 个答案:

答案 0 :(得分:3)

Sed不太擅长以编程方式检查多行的任务。这是我能得到的最接近的:

$ sed '/^$/{n;/^$/d}' file
abc

def

ghi


jkl

这个逻辑:如果你找到一个空行,请看下一行。如果下一行也是空白,则删除下一行。

这不会吞噬所有的行,因为它假设有一个有意的额外对,并将两个\n\n减少到两个\n


在基本awk中执行此操作:

$ awk 'NF > 0 {blank=0} NF == 0 {blank++} blank < 2' file
abc

def

ghi

jkl

这使用一个名为 blank 的变量,当字段数(NF)非零时为零,当它们为零(空白行)时递增。当连续空白行数小于2时,执行Awk的默认操作打印。

答案 1 :(得分:1)

使用awk(gnu或BSD)可以:

awk -v RS= -v ORS='\n\n' '1' file
abc

def

ghi

jkl

还使用perl

perl -pe '$/=""; s/(\n)+/$1$1/' file
abc

def

ghi

jkl

答案 2 :(得分:1)

perl -00 -pe 1 filename

将输入文件拆分为由2个或更多换行符分隔的“段落”,然后打印由单个空行分隔的段落:

perl -00 -pe 1 <<END
abc

def


ghi




jkl
END
abc

def

ghi

jkl

答案 3 :(得分:0)

这可能适合你(GNU sed):

sed '/^$/{:a;N;s/\n$//;ta}' file

这会用一个空行替换多个空白行。

但是,如果您想在每个非空白行后面放置一个空行,那么:

sed '/^$/d;G' file 

删除所有空白行,只将一个空白行附加到非空白行。

答案 4 :(得分:0)

在这里找到That's What I Sed(破坏者:比this solution慢)。

sed '/^$/N;/\n$/D' file

sed脚本的内容如下:

如果下一行为空,请删除当前行。

并且可以转换为以下伪代码:

 1 | # sed '/^$/N;/\n$/D' file
 2 | while not end of file :
 3 |   buffer = next line
 4 |   # /^$/N
 5 |   if buffer is empty :                        # /^$/
 6 |     buffer += "\n" + next line                # N
 7 |   end if
 8 |   # /\n$/D
 9 |   if buffer ends with "\n" :                  # /\n$/
10 |     delete first line in buffer and go to 5   # D
11 |   end if
12 |   print buffer
13 | end while

在正则表达式/^$/中,^$分别表示“缓冲区开始”和“缓冲区结束”。它们指的是缓冲区的边缘,而不是缓冲区的内容。

D命令执行以下任务:如果缓冲区包含换行符,则删除缓冲区的文本,直到第一个换行符,然后重新启动程序循环而不处理其余命令,而无需打印缓冲区,而无需读取新的输入行。

最后,请记住,sed会在处理行之前删除尾随的换行符。因此,在上面的代码中,如果下一行是Hello World!\n,则next line隐式引用Hello World!。还应考虑print重新添加尾随换行符。

更多详情,请访问https://www.gnu.org/software/sed/manual/sed.html

您现在可以尝试使用包含以下内容的文件了:

a\n
b\n
\n
\n
\n
c\n

好的,现在让我们看看为什么this solution更快。

sed脚本/^$/{:a;N;s/\n$//;ta}的读法如下:

如果当前行与/^$/相匹配,则执行{:a;N;s/\n$//;ta}

由于^$之间没有任何内容,因此我们可以这样改写:

如果当前行为空,则执行{:a;N;s/\n$//;ta}

这意味着sed为每个空行执行以下命令:

<身体>
步骤 命令 说明
1 :a 声明一个名为“ a”的标签。
2 N 在下一行前面加上换行符(\n)到当前行。
3 s/\n$// 用任何结尾的换行符(s)代替(/\n$/),不要包含任何内容(//)。
4 ta 如果执行了替换(在步骤3),则返回到标签“ a”(在步骤1),否则打印结果并移至下一行。

非空行仅按原样打印。知道了所有这些,我们可以使用以下伪代码描述整个过程:

 1 | # sed '/^$/{:a;N;s/\n$//;ta}' file
 2 | while not end of file :
 3 |   buffer = next line
 4 |   # /^$/{:a;N;s/\n$//;ta}
 5 |   if buffer is empty :               # /^$/
 6 |     :a                               # :a
 7 |     buffer += "\n" + next line       # N
 8 |     if buffer ends with "\n" :       # /\n$/
 9 |       remove last "\n" from buffer   # s/\n$//
10 |       go to :a (at 6)                # ta
11 |     end if
12 |   end if
13 |   print buffer
14 | end while

如您所见,两个sed脚本非常相似。实际上,s/\n$//;ta/\n$/D几乎相同。但是,第二个脚本跳过了第5步,因此它比第一个脚本更快。让这两个脚本的时间都填满〜10Mb的空行:

$ yes '' | head -10000000 > file
$ /usr/bin/time -f%U sed '/^$/N;/\n$/D' file > /dev/null
3.61
$ /usr/bin/time -f%U sed '/^$/{:a;N;s/\n$//;ta}' file > /dev/null
2.37

第二个脚本获胜。

答案 5 :(得分:-1)

为什么不删除所有空白行,然后在每行后添加一个空白行?对于您指定的输入文件tmp

sed '/^$/d' tmp|sed '0~1 a\ '
abc

def

ghi

jkl

如果空格(空格和制表符)计为&#34;空白&#34;为您排队,然后使用sed '/^\s*$/d' tmp|sed '0~1 a\ '代替。

请注意,这些解决方案最后会留下一个尾随空白行,因为我不确定是否需要这样做。轻松删除。

答案 6 :(得分:-1)

这为您提供了仅使用sed所需的内容:

sed '/^$/d' txt | sed -e $'s/$/\\\n/'

第一个sed命令删除所有空行,表示为&#34; ^ $&#34;。

第二个sed命令在每一行的末尾插入一个换行符。