63

I have a file that contains:

something



something else

something else again

I need a bash command, sed/grep w.e that will produce the following output

something

something else

something else again

In other words, I need to replace multiple blank lines with just a single blank line. grep/sed are line based. I've never found a BASH solution that would work on multi-line regex patterns.

3
  • Quick clarification question: Does the file ever have lines that aren't separated by a blank line? Commented May 28, 2009 at 18:28
  • 4
    Do you ever have duplicate lines that are not blank? If not, you could use uniq. Commented May 28, 2009 at 18:38
  • There are lines that are not separated by a blank line. There could be duplicate lines. Commented May 28, 2009 at 20:26

14 Answers 14

127

For BSD-derived systems (including GNU):

You just need cat with the -s option which causes it to remove repeated empty lines from its output:

cat -s

From man page: -s --squeeze-blank: suppress repeated empty output lines.

Sign up to request clarification or add additional context in comments.

10 Comments

for whatever reason that doesnt work for me cat -s file1 > file2
@qodeninja It didn't work for me either when I was working with files with Windows line endings. Maybe that could be the problem for you too? When I converted the files to Unix line endings cat -s worked fine for me.
in my version of cat on Solaris, the -s option has a different meaning "-s cat is silent about non-existent files"
@VictorZamanian Most of the time it is not possible to redirect back into a file like qodeninja did. For more information, read here: stackoverflow.com/questions/6696842/…
Note that it can be used through a pipe : some_output|cat -s.
|
42

I just solved this problem by sed. Even if this is a 7 year old question, someone may find this helpful, so I am writing my solution by sed here:

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

4 Comments

This works well for me, and because it's sed, I can use -i for in place fixes.
Wierdly this also removes the last 2 lines fo the file for me (on OSX sed)
sed '$!N;/^\n$/{$q;D;};P;D;' prevents the last line from being deleted on OSX sed. Also works on gnu sed.
Thanks, just so you know this is still useful info.
17
grep -A1 . <yourfile> | grep -v "^--$"

This grep solution works assuming you want the following:

Input

line1

line2
line3


line4



line5

Output

line1

line2
line3

line4

line5

2 Comments

I like it, very elegant solution
Frickin' brilliant, actually. I wouldn't have come up with this in a million years. Nice work. A slightly more robust version goes like this of course (to handle non-empty blank lines): grep -v -A1 '^[[:blank:]]*$' <file> | grep -v '^--$'
13

Actually, if you replace multiple newlines with a single newline, the output would be:

something
something else
something else again

You can achieve this by:

sed /^$/d FILE

1 Comment

This is correct, obviously :) What OP likely meant is to replace multiple "blank" (note that this is not necessarily empty, since lines can have invisible white space) with one empty line (which unless it is at the beginning or end of the sequence) means two newline chars.
5

Use awk:

awk '{ /^\s*$/?b++:b=0; if (b<=1) print }' file

Breakdown:

/^\s*$/?b++:b=0
    - ? :       the ternary operator
    - /^\s*$/   matches a blank line
    - b         variable that counts consecutive blank lines (b++).
                however, if the current line is non-blank, b is reset to 0.


if (b<=1) print
    print if the current line is non-blank (b==0)
          or if there is only one blank line (b==1).

By adjusting the regex, you can generalize it to other scenarios like squeezing multiple blank lines (">") in email: https://stackoverflow.com/a/59189823/12483961

1 Comment

I really like this, because it is the first solution that works on DOS files (with \r\n newlines) and because you can change the b<=1 to, say, b<=2 to allow up to 2 blank lines. Btw you can replace the file inline with: awk -i inplace
4

A solution with awk, which replaces several blank lines with a single blank line:

awk 'BEGIN{bl=0}/^$/{bl++;if(bl==1)print;else next}/^..*$/{bl=0;print}' myfile

Comments

4

Usually, if I find that sed can't do something I need, I turn to awk:

awk '
BEGIN {
    blank = 0;
}

/^[[:blank:]]*$/ {
     if (!blank) {
          print;
     }
     blank = 1;
     next;
}

{
     print;
     blank = 0;
}' file

Comments

4

If someone want use perl

perl -00pe0 < file

will do the same, as cat -s :)

Comments

3

This uses marco's solution on multiple files:

for i in *; do FILE=$(cat -s "$i"); echo "$FILE" > "$i"; done

Comments

2

Use python:

s = file("filename.txt").read()
while "\n\n\n" in s: s = s.replace("\n\n\n", "\n\n")
import sys
sys.stdout.write(s)

1 Comment

this is inefficient while loop
2

Python, with regular expression:

import re
import sys
sys.stdout.write(re.sub('\n{2,}','\n\n', sys.stdin.read()))

Comments

0

Super easy to do with vim. Just open the file and type the following:

:%s/\n\n\n*/\r\r/

That will reduce all blocks of more than 2 new lines to 2 new lines. Hope this helps!

Comments

-3

I take it that you'll probably want to remove lines that only have whitespace.

That can be done with:

sed /^[:space:]*$/d FILE

Comments

-6

Pipelining it to |uniq may be solution (if other than empty lines don't duplicate)

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.