如何使用 awk 重新排列列?

Kay*_*Kay 4 linux shell awk

我有一个包含 120 列的文件。其中一部分在这里,有 12 根柱子。

A1      B1     C1      D1       A2      B2     C2      D2       A3      B3      C3      D3     
4       4       5       2       3       3       2       1       9       17      25      33
5       6       4       6       8       2       3       5       3       1       -1      -3
7       8       3       10      13      1       4       9       -3      -15     -27     -39
9       10      2       14      18      0       5       13      -9      -31     -53     -75
11      12      1       18      23      -1      6       17      -15     -47     -79     -111
13      14      0       22      28      -2      7       21      -21     -63     -105    -147
15      16      -1      26      33      -3      8       25      -27     -79     -131    -183
17      18      -2      30      38      -4      9       29      -33     -95     -157    -219
19      20      -3      34      43      -5      10      33      -39     -111    -183    -255
21      22      -4      38      48      -6      11      37      -45     -127    -209    -291
Run Code Online (Sandbox Code Playgroud)

我想通过将所有 A 列放在一起(A1 A2 A3 A4)并将所有 B 列(B1 B2 B3 B4)、Cs(C1 C2 C3 C4)、Ds(D1 D2 D3 D4)放在一起来重新排列它。

我希望将列打印为

A1 A2 A3 A4 B1 B2 B3 B4 C1 C2 C3 C4 D1 D2 D3 D4
 
Run Code Online (Sandbox Code Playgroud)

我的脚本是:

#!/bin/sh
sed -i '1d' input.txt
for i in {1..4};do
    j=$(( 1 + $(( 3 * $((  i - 1 )) ))  ))
awk '{print $'$j'}' input.txt >> output.txt
done
for i in {1..4};do
    j=$(( 2 + $(( 3 * $((  i - 1 )) ))  ))
awk '{print $'$j'}' input.txt >> output.txt
done
for i in {1..4};do
    j=$(( 3 + $(( 3 * $((  i - 1 )) ))  ))
awk '{print $'$j'}' input.txt >> output.txt
done
Run Code Online (Sandbox Code Playgroud)

它将全部打印在一列中。

Rav*_*h13 6

这里有两种通用方法解决方案,无需对 Input_file 中的字段编号进行硬编码,值可以按任何顺序出现,并且它会自动对它们进行排序。使用 GNU 编写并awk使用所示示例进行测试。

第一个解决方案:遍历所有行及其各自的字段,然后按值排序以对标头执行索引。

awk '
FNR==1{
  for(i=1;i<=NF;i++){
     arrInd[i]=$i
  }
  next
}
{
  for(i=1;i<=NF;i++){
     value[FNR,arrInd[i]]=$i
  }
}
END{
  PROCINFO["sorted_in"]="@val_num_asc"
  for(i in arrInd){
     printf("%s%s",arrInd[i],i==length(arrInd)?ORS:OFS)
  }
  for(i=2;i<=FNR;i++){
     for(k in arrInd){
        printf("%s%s",value[i,arrInd[k]],k==length(arrInd)?ORS:OFS)
     }
  }
}
'   Input_file
Run Code Online (Sandbox Code Playgroud)

或者,如果您想以表格格式获得输出,请在上述解决方案中进行小调整。

awk '
BEGIN { OFS="\t" }
FNR==1{
  for(i=1;i<=NF;i++){
    arrInd[i]=$i
  }
  next
}
{
  for(i=1;i<=NF;i++){
    value[FNR,arrInd[i]]=$i
  }
}
END{
  PROCINFO["sorted_in"]="@val_num_asc"
  for(i in arrInd){
    printf("%s%s",arrInd[i],i==length(arrInd)?ORS:OFS)
  }
  for(i=2;i<=FNR;i++){
    for(k in arrInd){
       printf("%s%s",value[i,arrInd[k]],k==length(arrInd)?ORS:OFS)
    }
  }
}
' Input_file | column -t -s $'\t'
Run Code Online (Sandbox Code Playgroud)

第二个解决方案: 与第一个解决方案几乎相同的概念,这里在条件内遍历数组,而不是在END此程序的块中显式调用它。

awk '
BEGIN { OFS="\t" }
FNR==1{
  for(i=1;i<=NF;i++){
    arrInd[i]=$i
  }
  next
}
{
  for(i=1;i<=NF;i++){
    value[FNR,arrInd[i]]=$i
  }
}
END{
  PROCINFO["sorted_in"]="@val_num_asc"
  for(i in arrInd){
    printf("%s%s",arrInd[i],i==length(arrInd)?ORS:OFS)
  }
  for(i=2;i<=FNR;i++){
    for(k in arrInd){
       printf("%s%s",value[i,arrInd[k]],k==length(arrInd)?ORS:OFS)
    }
  }
}
' Input_file | column -t -s $'\t'
Run Code Online (Sandbox Code Playgroud)


Mar*_*eed 5

是不是只有A、B、C、D、A、B、C、D?像这样的东西应该可以工作(尽管它是快速、肮脏和具体的):

awk -v OFS='\t' '{
    for (i=0; i<4; ++i) {  # i=0:A, i=1:B,etc.
       for (j=0; 4*j+i<NF; ++j) {
         if (i || j) printf "%s", OFS;
         printf "%s", $(4*j+i+1);
       }
    }
    printf "%s", ORS;
}'
Run Code Online (Sandbox Code Playgroud)