Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to transfer the data of columns to rows (with awk)?

Tags:

linux

awk

rows

I have a file like this:

n A B C D 
1 01 02 01 01
2 02 02 01 01

and I want to transfer the columns by rows, so the output should be like this:

n 1 2
A 01 02
B 02 02
C 01 01 
D 01 01

I have wrote this command:

awk '{ for (i=1;i<=NF;i++ ) printf $i " " }' file.txt > out-file.txt

the problem is that this command put everything on one line! so the output is like this:

n 1 2 A 01 02 B 02 02 C 01 01 D 01 01
like image 525
mahmood Avatar asked Mar 02 '12 14:03

mahmood


3 Answers

This might work:

awk '{
       for (f = 1; f <= NF; f++) { a[NR, f] = $f } 
     }
     NF > nf { nf = NF }
     END {
       for (f = 1; f <= nf; f++) {
           for (r = 1; r <= NR; r++) {
               printf a[r, f] (r==NR ? RS : FS)
           }
       }
    }' YOURINPUT

See it in action @ Ideone.

like image 177
Zsolt Botykai Avatar answered Oct 17 '22 06:10

Zsolt Botykai


This uses of arrays of arrays which is a gawk extension:

tp(){ awk '{for(i=1;i<=NF;i++)a[i][NR]=$i}END{for(i in a)for(j in a[i])printf"%s"(j==NR?"\n":FS),a[i][j]}' "FS=${1-$'\t'}";}

Another option is to use rs (which is a BSD utility that also comes with macOS):

$ cat /tmp/a
n A B C D
1 01 02 01 01
2 02 02 01 01
$ rs -c' ' -C' ' -T</tmp/a|sed 's/.$//'
n 1 2
A 01 02
B 02 02
C 01 01
D 01 01

-c changes the input column separator, -C changes the output column separator, and -T transposes rows and columns.

When an output column separator is specified using -C, an extra column separator character is added to the end of each output line, but you can remove it with sed 's/.$//':

$ seq 4|paste -d, - -|rs -c, -C, -T
1,3,
2,4,
$ seq 4|paste -d, - -|rs -c, -C, -T|sed 's/.$//'
1,3
2,4

The rs command fails in the case where the first line ends with one or more empty columns, because the number of columns is determined based on the number of columns on the first line:

$ rs -c, -C, -T<<<$'1,\n3,4'
1,3,4,
like image 10
nisetama Avatar answered Oct 17 '22 06:10

nisetama


Save this script as transpose.awk and chmod u+x transpose.awk. It's a modification of Tim Sherwood's transpose.

#!/usr/bin/gawk -f

BEGIN {
    max_x =0;
    max_y =0;
}

{
    max_y++;
    for( i=1; i<=NF; i++ )
    {
        if (i>max_x) max_x=i;
        A[i,max_y] = $i;
    }
}

END {
    for ( x=1; x<=max_x; x++ )
    {
        for ( y=1; y<=max_y; y++ )
        {
            if ( (x,y) in A ) printf "%s",A[x,y];
            if ( y!=max_y ) printf " ";
        }
        printf "\n";
    }
}

Example:

$ ./transpose.awk example
n 1 2
A 01 02
B 02 02
C 01 01
D 01 01
like image 3
Eduardo Ivanec Avatar answered Oct 17 '22 07:10

Eduardo Ivanec