zhuguowei
zhuguowei

Reputation: 8487

how to find continuous blank lines and convert them to one

I have a file -- a, and exist some continues blank line(more than one), see below:

cat a
1

2


3



4

5

So first I want to know if exist continues blank lines, I tried

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

nothing output. So I have to use below manner

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

So I want to know if exist other shell command could easily implement this? then if exist two and more blank lines I want to convert them to one? see below

1

2

3

4

5

at first I tried below shell

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

it does not work, then I tried this shell

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

this time it works. And also I want to know if exist other manner could implement this?

Upvotes: 3

Views: 732

Answers (6)

Sundeep
Sundeep

Reputation: 23667

Well, if your cat implementation supports

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

then it is as simple as

$ cat -s a
1

2

3

4

5

Also, both -s and -n for numbering lines is likely to be available with less command as well.

remark: lines containing only blanks will not be suppressed.

If your cat does not support -s then you could use:

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

or if you want to guarantee a blank line after every record, including at the end of the output even if none was present in the input, then:

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

If your input contains lines of all white space and you want them to be treated just like lines of non white space (like cat -s does, see the comments below) then:

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

and to guarantee a blank line at the end of the output:

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

Upvotes: 5

kvantour
kvantour

Reputation: 26481

remark: This is a copy from my answer here


A very quick way is using

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

How does this work:

knowns the concept records (which is by default lines) and you can define a record by its record separator RS. If you set the value of RS to an empty string, it will match any multitude of empty lines as a record separator. The value ORS is the output record separator. It states which separator should be printed between two consecutive records. This is set to two <newline> characters. Finally, the statement 1 is a shorthand for {print $0} which prints the current record followed by the output record-separator ORS.

note: This will, just as cat -s keep lines with only blanks as actual lines and will not suppress them.

Upvotes: 1

Abis
Abis

Reputation: 165

1) awk solution

$ 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 solution

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 Explanation:

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

--If input is blank, if it is the last line, just print, else append to the holdspace and delete the pattern space and start new cycle

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

--If input is not blank, exchange content of the p space and h space and check if h space contains \n. if yes, jump to s, if not jump to f

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

--If blank lines are present in h space, then append \n to p space, then clear hold space , then print p space and delete p space

:f { x; p; d; }

--If blank lines are absent in h space, then print p space and delete p space

Upvotes: 0

valrog
valrog

Reputation: 236

Another awk solution:

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

2

3

4

5

It checks if the line is not empty by testing if NF (number of fields) is not zero. It it matches, print the line as default action. ORS (output record separator) is set to 2 newline characters, so there is an empty line between non-empty lines.

Upvotes: 0

anubhava
anubhava

Reputation: 785156

This awk command should work to produce an output with 2 line breaks at each line:

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

1

2

3

4

5

This awk is using:

  • -v RS=: sets empty input record separator so that each empty line becomes record separator
  • printf "%s%s", $0, ORS: prints each line with single line break
  • (RT ~ /\n{2,}/ ? ORS : ""): prints additional line break if input record separator has more than 2 line breaks

You may use perl as well in slurp mode:

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

1

2

3

4

5

Command breakup:

  • -0777 Slurp mode to read entire file
  • 's/\R{2,}/\n\n/g' Match 2 or more line breaks and replace by 2 line breaks

Upvotes: 3

MauricioRobayo
MauricioRobayo

Reputation: 2356

You can --squeeze-repeats with tr and then use sed to insert just a new line:

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

Upvotes: 1

Related Questions