awk has a builtin feature to process input content paragraph wise (by setting RS to an empty string). But, did you know that cat, less and grep can also be used to squeeze empty lines?

cat -s (and less -s) will squeeze multiple empty lines in the input to a single empty line in the output. Here's an example:

$ cat ip.txt
hello




world

apple
banana
cherry


tea coffee
chocolate
$ cat -s ip.txt
hello

world

apple
banana
cherry

tea coffee
chocolate

Here's an example with empty lines at the start/end of the input:

$ printf '\n\n\ndragon\n\n\nunicorn\n\n\n'



dragon


unicorn


$ printf '\n\n\ndragon\n\n\nunicorn\n\n\n' | cat -s

dragon

unicorn

And here's a solution with awk. Unlike the -s option, this will completely remove empty lines at the start/end of the input.

$ awk -v RS= '{print s $0; s="\n"}' ip.txt
hello

world

apple
banana
cherry

tea coffee
chocolate

$ printf '\n\n\ndragon\n\n\nunicorn\n\n\n' | awk -v RS= '{print s $0; s="\n"}'
dragon

unicorn

The awk solution would be easier to extend, given its programmable features. For example, two empty lines between the groups:

$ awk -v RS= '{print s $0; s="\n\n"}' ip.txt
hello


world


apple
banana
cherry


tea coffee
chocolate

And here's a surprising GNU grep solution, with a customizable group separator:

# single empty line
$ grep --group-separator= -A0 '.' ip.txt
hello

world

apple
banana
cherry

tea coffee
chocolate

# double empty line
# empty lines at the start/end of the input are removed too
$ printf '\n\n\ndragon\n\n\nunicorn\n\n\n' | grep --group-separator=$'\n' -A0 '.'
dragon


unicorn

Video demo:


info See also my Command line text processing with GNU Coreutils, GNU AWK and CLI text processing with GNU grep and ripgrep ebooks.