Reputation: 133
I have this simplified table of numbers constituted by 2 columns and several rows. The point here is for each column, take the values and order them in rows so that in each row there are 4 values. This file.txt:
1 2
1 2
1 2
1 2
1 2
1 2
1 2
1 2
1 2
And this is the result that I want:
1 1 1 1
1 1 1 1
1
2 2 2 2
2 2 2 2
2
I do the following, creating a script.awk for clarity.
awk -f script.awk file.txt
Where script.awk is
{for (i=1;i<=NF;i++)
printf "%s" (NR %4==0 ? RS:FS), $i;}
But it does not wok. I know that the following command works for one column, but I do not understand why it does not work for a loop in each column.
{printf "%s" (NR %4==0 ? RS:FS), $1;}
If poossible, I would like an explanation of the sommands used, as I am new to this language. Thanks!
Upvotes: 1
Views: 415
Reputation: 74615
The problem with your approach is that awk goes through each line (record) one at a time, so the loop in your block will apply the first field in the first line, the second field, then move on to the next line. This doesn't do what you want, as you need all the elements of the first field before you can do anything.
One option is to build an array of both fields, then print them when you get to the end of the file:
awk 'function p(a) { s=""; for(i=1;i<=NR;++i) s=s a[i] (i%4==0 ? RS:FS); print s }
{ a[NR]=$1; b[NR]=$2 }
END { p(a); p(b) }' file
Upvotes: 1
Reputation: 195059
I would post a generic solution:
awk '{for (i=1;i<=NF;i++) a[i,NR]=$i; }END{
for(i=1;i<=NF;i++) {
for(j=1;j<=NR;j++)
printf "%s%s", a[i,j],(j%4==0||j==NR?"\n":" ");
}
}' file
this works for dynamic columns in your input file, e.g.:
kent$ cat f
1 2 3 4
1 2 3 4
1 2 3 4
1 2 3 4
1 2 3 4
1 2 3 4
1 2 3 4
1 2 3 4
1 2 3 4
kent$ awk '{for (i=1;i<=NF;i++) a[i,NR]=$i; }END{
for(i=1;i<=NF;i++) {
for(j=1;j<=NR;j++)
printf "%s%s", a[i,j],(j%4==0||j==NR?"\n":" ");
}
}' f
1 1 1 1
1 1 1 1
1
2 2 2 2
2 2 2 2
2
3 3 3 3
3 3 3 3
3
4 4 4 4
4 4 4 4
4
you just need to change the 4
to control how many cols in your output. it is also easy to be put as an argument with awk -v cols="$var" ...
Upvotes: 3
Reputation: 21
Another way, use awk
and sort
:
cat file|awk '{printf("%s\n%s\n",$1,$2)}'|sort|awk 'BEGIN{ORS=" "}
{if(NR==1){l=$1};if($1!=l){printf("\n");NR=1};
print $1;if(NR%4==0){printf("\n")};l=$1}'
1 1 1 1
1 1 1 1
1
2 2 2 2
2 2 2 2
2
Upvotes: 2
Reputation: 785156
Using awk
you can do:
awk '{a[$1]++; b[$2]++} END{for (i=1; i<=a[$1]; i++) printf "%s%s", $1, (i%4)?FS:ORS ;
print ""; for (i=1; i<[$2]; i++) printf "%s%s", $2, (i%4)?FS:ORS; print ""}' file
1 1 1 1
1 1 1 1
1
2 2 2 2
2 2 2 2
2
Upvotes: 2