如何找到连续的空白行并将它们转换为一行

时间:2017-08-07 14:29:55

标签: shell awk

我有一个文件 - 一个,并且存在一些连续的空行(多个),见下文:

cat a
1

2


3



4

5

首先我想知道是否存在继续空行,我试过

cat a | grep '\n\n\n'

没有输出。所以我必须使用以下方式

vi a 
:set list
/\n\n\n

所以我想知道是否存在其他shell命令可以轻松实现这个? 然后,如果存在两个或更多的空行我想将它们转换为一个?见下文

1

2

3

4

5

起初我尝试了下面的shell

sed 's/\n\n\(\n\)*/\n\n/g' a

它不起作用,然后我尝试了这个shell

cat a | tr '\n' '$' | sed 's/$$\(\$\)*/$$/g' | tr '$' '\n'

这次它有效。而且我想知道是否存在其他方式可以实现这个?

6 个答案:

答案 0 :(得分:6)

好吧,如果您的cat实施支持

   -s, --squeeze-blank
          suppress repeated empty output lines

然后它就像

一样简单
$ cat -s a
1

2

3

4

5

此外,编号行的-s-n也可能与less命令一起使用。

备注:只包含空格的行不会被删除。

如果您的cat不支持-s,那么您可以使用:

awk 'NF||p; {p=NF}'

或者如果你想在每条记录后保证一个空行,包括在输出结尾,即使输入中没有,那么:

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

如果您的输入包含所有空格的行,并且您希望它们被视为非空白行(如cat -s那样,请参阅下面的注释),然后:

awk '/./||p; {p=/./}'

并保证输出结尾处有一个空行:

awk '/./||p; {p=/./} END{if (p) print ""}'

答案 1 :(得分:3)

awk命令应该可以生成每行包含2个换行符的输出:

awk -v RS= '{printf "%s%s", $0, ORS (RT ~ /\n{2,}/ ? ORS : "")}' file

1

2

3

4

5

这个awk正在使用:

  • -v RS=:设置空输入记录分隔符,以便每个空行成为记录分隔符
  • printf "%s%s", $0, ORS:使用单换行打印每一行
  • (RT ~ /\n{2,}/ ? ORS : ""):如果输入记录分隔符有超过2个换行符,则打印其他换行符

您也可以在slurp模式下使用perl

perl -0777 -pe 's/\R{2,}/\n\n/g' file

1

2

3

4

5

命令分手:

  • -0777 Slurp模式读取整个文件
  • 's/\R{2,}/\n\n/g'匹配2个或更多换行符并替换为2个换行符

答案 2 :(得分:1)

您可--squeeze-repeats使用tr,然后使用sed插入新行:

 <a tr -s '\n' | sed 'G'

答案 3 :(得分:1)

备注:这是我的答案here

的副本

一种非常快速的方法是使用

awk 'BEGIN{RS="";ORS="\n\n"}1' 

这是如何工作的:

知道概念记录(默认情况下为几行),您可以通过其记录分隔符RS定义记录。如果将RS的值设置为空字符串,则它将匹配任何空行作为记录分隔符。值ORS是输出记录分隔符。它指出应在两个连续记录之间打印哪个分隔符。设置为两个字符。最后,语句1{print $0}的简写,它打印当前记录,然后打印输出记录分隔符ORS

注意:就像cat -s那样,仅保留空白行作为实际行,而不会隐藏它们。

答案 4 :(得分:0)

另一个解决方案:

awk 'NF' ORS="\n\n" a
1

2

3

4

5

通过测试NF(字段数)是否为零来检查线路是否为空。它匹配,打印行作为默认动作。 ORS(输出记录分隔符)设置为2个换行符,因此非空行之间有一个空行。

答案 5 :(得分:0)

1)awk解决方案

$ echo "a\n\n\nb\n\n\nc\n\n\n" | awk 'BEGIN{b=0} /^$/{b=1;next} {printf "%s%s\n", b==1?"\n":"",$0} {b=0} END{printf "%s",b==1?"\n":""}'
        a

        b

        c

$ 

2)sed解决方案

sed '

/^$/{ ${ p; d; }; H; d; } 

/^$/!{ x; s/^\(\n\{1,\}\)$/\1/; ts; Tf; } 

:s { x; s/\(.*\)/\n\1/; x; s/.*//; x; p; d; } 

:f { x; p; d; }

'

SED说明:

/^$/{ ${ p; d; }; H; d; }

- 如果输入为空白,如果是最后一行,则只需打印,否则附加到保留空间并删除模式空间并开始新的循环

/^$/!{ x; s/^\(\n\{1,\}\)$/\1/; ts; Tf; } 

- 如果输入不为空,则交换p空间和h空格的内容,并检查h空格是否包含\ n。如果是,跳转到s,如果没有跳转到f

:s { x; s/\(.*\)/\n\1/; x; s/.*//; x; p; d; }

- 如果h空格中存在空行,则将\ n附加到p空格,然后清除保留空间,然后打印p空格并删除p空格

:f { x; p; d; }

- 如果h空格中没有空行,则打印p空格并删除p空格