awk-在不同的行中打印一列

时间:2014-08-01 10:28:37

标签: bash awk

我有这个简化的数字表,由2列和几行组成。这里的要点是每列,取值并按行排序,以便每行有4个值。这个file.txt:

1   2   
1   2   
1   2   
1   2   
1   2   
1   2   
1   2   
1   2   
1   2   

这就是我想要的结果:

1    1    1    1
1    1    1    1    
1   

2    2    2    2    
2    2    2    2    
2   

我执行以下操作,为了清楚起见创建了script.awk。

awk -f script.awk file.txt

其中script.awk是

{for (i=1;i<=NF;i++)
     printf "%s" (NR %4==0 ? RS:FS), $i;}

但它没有炒作。我知道以下命令适用于一列,但我不明白为什么它不适用于每列中的循环。

{printf "%s" (NR %4==0 ? RS:FS), $1;}

如果不可能,我想解释所使用的sommands,因为我是这种语言的新手。谢谢!

4 个答案:

答案 0 :(得分:3)

我会发布一个通用解决方案:

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

这适用于输入文件中的动态列,例如:

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

您只需更改4即可控制输出中的cols数量。它也很容易作为awk -v cols="$var" ...

的参数

答案 1 :(得分:2)

使用awk即可:

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

答案 2 :(得分:2)

另一种方法,使用awksort

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

答案 3 :(得分:1)

你的方法的问题是awk一次遍历每一行(记录),所以你的块中的循环将应用第一行中的第一个字段,第二个字段,然后移到下一行。这不能做你想做的事情,因为你需要先做第一个字段的所有元素才能做任何事情。

一个选项是构建两个字段的数组,然后在到达文件末尾时打印它们:

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