lightsnail lightsnail - 2 months ago 11
Linux Question

Loop every three consecutive rows in linux

I have a file

hundred.txt
containing 100 rows.

For example:

1 0 0 1
1 1 0 1
1 0 1 0
1 0 1 0
0 1 1 0
....
1 0 0 1


I need to manipulate some calculations within every 3 consecutive rows, for instance, I need to use the Row1-Row3 first to do my calculation:

1 0 0 1
1 1 0 1
1 0 1 0


then the Row2-Row4:

1 1 0 1
1 0 1 0
1 0 1 0


...... the Row98-Row100.

Each output will generate a file (e.g. Row1.txt, Row2.txt,... Row98.txt), How can I solve this problem? Thank you.

Answer

awk to the rescue!

$ awk 'NR>2{printf "%s", a2 ORS a1 ORS $0 ORS > FILENAME"."(++c)}
           {a2=a1;a1=$0}' file

for the input file

$ cat file
1 0 0 1
1 1 0 1
1 0 1 0
1 0 1 0
0 1 1 0

generates these 3

$ head file.{1..3}
==> file.1 <==
1 0 0 1
1 1 0 1
1 0 1 0

==> file.2 <==
1 1 0 1
1 0 1 0
1 0 1 0

==> file.3 <==
1 0 1 0
1 0 1 0
0 1 1 0

you can embed your computation is the script and output only the results but you didn't provide any details on that.

Explanation

NR>2 starting third row
printf ... start printing last 3 rows
> FILENAME"."(++c) to a file derived from input filename with counter suffix

a2=a1;a1=$0 update last two rows

if your rolling window is small n you can scale this script by changing NR>(n-1) and keeping track of last rows in a(n-1)...a1 and printing accordingly. If n is large, better to use a array (or better a circular array).

This is perhaps the most generic version...

$ awk -v n=3 'NR>n-1{fn=FILENAME"."c; 
                     for(i=c+1;i<c+n;i++) printf "%s\n", a[(i-n)%n] > fn;
                     print > fn} 
                    {a[(c++)%n]=$0}' file