linux - 如何使用 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

我想通过将所有 A 列放在一起 (A1 A2 A3 A4) 以及类似地所有 Bs (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
 

我的脚本是:

#!/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

它正在打印所有内容在一栏中。

最佳答案

这里有两个通用方法解决方案,无需对 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

OR 如果您想获得表格格式的输出,请对上述解决方案进行小的调整。

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'


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

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=1;i<=FNR;i++){
    if(i==1){
       for(k in arrInd){
          printf("%s%s",arrInd[k],k==length(arrInd)?ORS:OFS)
       }
    }
    else{
       for(k in arrInd){
          printf("%s%s",value[i,arrInd[k]],k==length(arrInd)?ORS:OFS)
       }
    }
  }
}
' Input_file | column -t -s $'\t'

https://stackoverflow.com/questions/73286211/

相关文章:

java - @EnableGlobalMethodSecurity 在新的 spring boot

c# - 删除数组中的当前元素

javascript - 如何迭代两个对象并根据 JS 中的另一个更新一个值?

java - 流迭代不使用最后一个值

regex - 使用 awk 只包含以特定值开头的列?

c++ - 使用 enable_if 对类方法进行部分模板特化

javascript - 无法从非 EcmaScript 模块导入命名导出 'cloneElemen

javascript - 过滤 2 个数组以检查父子是否

rust - 将闭包指定为返回类型的替代方法?

r - 与 R 中的日期相关联的条件累积和