Tuesday, May 24, 2011

Bash insert newline after every 3 lines


-----------
Input file:
-----------
$ cat file.txt
FR 24
AA 33
EE 34
EE 46
BE 30
AA 31
DE 90
AL 10
AA 50
FR 67
EE 94
AA 80
NK 80

---------
Required:
---------
Insert a newline after every 3 lines of the above file. i.e. required output:
FR 24
AA 33
EE 34

EE 46
BE 30
AA 31

DE 90
AL 10
AA 50

FR 67
EE 94
AA 80

NK 80

----------
Solutions:
----------
a) Using awk:
$ awk '!( NR % 3 ) {$0 = $0"\n"} 1' file.txt

Which is same as:
$ awk '!( NR % 3 ) {$0 = $0"\n"} {print}' file.txt

b) A UNIX bash script to achieve this:
#!/bin/sh
c=0
while read line
do
((s=c%3))
if [ "$s" -eq 0 ]; then
echo -e "\n$line"
else
echo "$line"
fi
((c=c+1))
done < file.txt | sed '1d'

Following if-else block
 
if [ "$s" -eq 0 ]; then
echo -e "\n$line"
else
echo "$line"
fi

can also be written as:
[ "$s" -eq 0 ] && echo -e "\n$line" || echo "$line"

---------------------------
Any other alternative ?
---------------------------
Feel free to comment any other alternative to achieve this, much appreciated, thanks.

Related posts:
- UNIX Bash while loop sum issue explained
- Difference between awk NR and FNR

9 comments:

Paul said...

Using sed:

sed 'n;n;G' file.txt

Jadu Saikia said...

@Paul, great solution, thanks. As I understood from one of the tutorial sed 'G' adds a new line to the pattern space, and copies the hold space after the new line. Thanks again.

Adithya Kiran said...

The same result can be achieved using vim editor:

:%s/\v(.*\n){3}/&\r

Some what complicated to understand though, but in place editing with vim right..:)

Jadu Saikia said...

@Adithya, thanks very much for this very useful vim tip. All your tips are really of great help.

kon said...

when using GNU sed you can also use

sed '0~3G'

Linux/Unix/System Admin etc said...

Hi Jadu,

May be you can help me on this , I am regular visitor of your blog from Switzerland. I have an issue

how to ignore this error message

syntax error on line 1, teletype

EXPIRE=`echo $current_date - $lastpass | /bin/bc`

I am writing a script for password notification based on the last password change and for that I need to change the date value to days.

It's Solaris box.

Rgds
Naveen

Jadu Saikia said...

@Linux/Unix/System Admin etc,

Hey nice to know that you are a regular reader of unstableme.blogspot.com. Thanks.

I don't have Solaris OS to test this, but looks like "syntax error on line 1, teletype" is usually thrown by "bc" utility. Not sure if either $current_date or $lastpass has a illegal value. Could you please echo both the numbers for a test

echo $current_date
echo $lastpass

Thanks.

Naveen said...

Thanks for the reply , I managed somehow....to ignore teletype error message.

if [ "a" != "a${lastpass}" ]; then
EXPIRE=`echo $current_date - $lastpass | /bin/bc`

else
echo "$userid has Empty Date"
fi

Jadu Saikia said...

@Naveen, thanks for sharing that.

As I mentioned here : http://unstableme.blogspot.com/2007/06/double-brackets-for-arithmetic.html

you can also do the following for arithmetic evaluation:

((EXPIRE=current_date-lastpass))

Regards,
Jadu

© Jadu Saikia www.UNIXCL.com