0

I would like to reverse a file however in this file I have records 3 lines each

a1
a2
a3
...
x1
x2
x3

and I would like to get such file

x1
x2
x3
...
a1
a2
a3

I use Linux so tail -r doesn't work for me.

5 Answers 5

2

You can do this all in awk, using an associative array:

BEGIN { j=1 }
++i>3 { i=1; ++j }
{ a[j,i]=$0 }
END{ for(m=j;m>0;--m)
       for(n=1;n<=3;++n) print a[m,n]
}

Run it like this:

awk -f script.awk file.txt

or of course, if you prefer a one-liner, you can use this:

awk 'BEGIN{j=1}++i>3{i=1;++j}{a[j,i]=$0}END{for(m=j;m>0;--m)for(n=1;n<=3;++n)print a[m,n]}' file.txt

Explanation

This uses two counters: i which runs from 1 to 3 and j, which counts the number of groups of 3 lines. All lines are stored in the associative array a and printed in reverse in the END block.

Testing it out

$ cat file
a1
a2
a3
b1
b2
b3
x1
x2
x3
$ awk 'BEGIN{j=1}++i>3{i=1;++j}{a[j,i]=$0}END{for(m=j;m>0;--m)for(n=1;n<=3;++n)print a[m,n]}' file
x1
x2
x3
b1
b2
b3
a1
a2
a3
Sign up to request clarification or add additional context in comments.

Comments

2

This is so ugly that I'm kinda ashamed to even post it... so I guess I'll delete it as soon as a more decent answer pops up.

tac /path/to/file | awk '{ a[(NR-1)%3]=$0; if (NR%3==0) { print a[2] "\n" a[1] "\n" a[0] }}'

Comments

1

With the file:

~$ cat f
1
2
3
4
5
6
7
8
9

with awk: store the first line in a, then append each line on top of a and for the third line print/reinitialise:

~$ awk '{a=$0"\n"a}NR%3==0{print a}NR%3==1{a=$0}' f
3
2
1
6
5
4
9
8
7

then use tac to reverse again:

~$ awk '{a=$0"\n"a}NR%3==0{print a}NR%3==1{a=$0}' f | tac
7
8
9
4
5
6
1
2
3

Comments

1

Another way in awk

awk '{a[i]=a[i+=(NR%3==1)]?a[i]"\n"$0:$0}END{for(i=NR/3;i>0;i--)print a[i]}' file

Input

a1
a2
a3
x1
x2
x3
b1
b2
b3

Output

b1
b2
b3
x1
x2
x3
a1
a2
a3

Comments

1

Here's a pure Bash (Bash≥4) possibility that should be okay for files that are not too large. We also assume that the number of lines in your file is a multiple of 3.

mapfile -t ary < /path/to/file
for((i=3*(${#ary[@]}/3-1);i>=0;i-=3)); do
    printf '%s\n' "${ary[@]:i:3}"
done

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.