【问题标题】:How do I put this AWK function in a for loop to extract columns?如何将此 AWK 函数放入 for 循环中以提取列?
【发布时间】:2021-02-08 09:00:23
【问题描述】:

我有几十个文件(例如 fA.txt、fB.txt 和 fc.txt),并且想要 fALL.txt 中所示的输出。

fA.t​​xt: id V W X Y Z 1 2 4 8 16 b 3 6 13 17 18 c 5 1 20 4 8 fB.txt: id F G H J K 2 5 9 7 12 b 4 9 12 3 19 c 6 13 2 40 7 fC.txt: id L M N O P 7 2 19 8 16 b 8 6 12 23 47 c 91 11 15 19 80 期望的输出 下降.txt: id fA_V fB_F fC_L 1 2 7 b 3 4 8 c 5 6 91 id fA_W fB_G fC_M 一个 2 5 2 b 6 9 6 1 13 11 id fA_X fB_H fC_N 一个 4 9 19 乙 13 12 12 20 2 15 id fA_Y fB_J fC_O 一个 8 7 8 b 17 3 23 c 4 40 19 id fA_Z fB_K fC_P 16 12 16 b 18 19 47 c 8 7 80

我在这个站点上看到了以下 AWK 代码,它适用于只有 2 列的输入文件。 'NR==FNR{a[FNR]=$0; next} {a[FNR] = a[FNR] OFS $2} END{for (i=1;i<=FNR;i++) print a[i]}' file1 file2 file3 就我而言,我对上面的内容进行了如下修改,它适用于提取第二列: 'NR==FNR{a[FNR]=$1 OFS $2; next} {a[FNR] = a[FNR] OFS $2} END{for (i=1; i<=FNR; i++) print a[i]}' file1 file2 file3 我已尝试将上述内容放入 for 循环中以提取后续列,但未成功。任何有用的提示将不胜感激。 所需输出中的第一个数据块是每个输入文件的第二列,其标题与相应输入文件中的文件名和列标题连接。随后的块是每个输入文件的第三、第四、第五列。

【问题讨论】:

  • 欢迎来到 SO,感谢您在问题中分享您的努力。您能否在您的问题中(不在 cmets 中)提及获取示例显示输出的逻辑,因为不清楚您如何获得预期的输出,谢谢。
  • 按要求添加逻辑
  • 这还不清楚。我们如何将输出分成更小的部分?显而易见且自然的安排是使用单个矩阵,如果您发现要提取的新特征在其中添加更多列(或者更自然的倒矩阵,您为每个新特征添加一行,为每个新特征添加一个新列文件)。

标签: shell for-loop multidimensional-array awk


【解决方案1】:

这个gnu awk 应该适合你。

cat tab.awk
BEGIN {
   OFS = "\t"
   for (i=1; i<=ARGC; ++i) {
      fn = ARGV[i]
      sub(/\.[^.]+$/, "_", fn)
      fhdr[i] = fn
   }
}
!seen[$1]++ {
   keys[++k] = $1
}
{
   for (i=2; i<=NF; ++i)
      map[$1][i] = map[$1][i] (map[$1][i] == "" ? "" : OFS) (FNR == 1 ? fhdr[ARGIND] : "") $i
}
END {
   for (i=2; i<=NF; ++i) {
      for (j=1; j<=k; j++) {
         key = keys[j]
         print key, map[key][i]
      }
      print ""
   }
}

然后将其用作:

awk -f tab.awk f{A,B,C}.txt
id  fA_V  fB_F  fC_L
a   1     2     7
b   3     4     8
c   5     6     91

id  fA_W  fB_G  fC_M
a   2     5     2
b   6     9     6
c   1     13    11

id  fA_X  fB_H  fC_N
a   4     9     19
b   13    12    12
c   20    2     15

id  fA_Y  fB_J  fC_O
a   8     7     8
b   17    3     23
c   4     40    19

id  fA_Z  fB_K  fC_P
a   16    12    16
b   18    19    47
c   8     7     80


说明:

 BEGIN {
   OFS = "\t"                   # Use output field separator as tab
   for (i=1; i<=ARGC; ++i) {    # for each filename in input
      fn = ARGV[i]
      sub(/\.[^.]+$/, "_", fn)  # remove anything after dot with a _
      fhdr[i] = fn              # and save it in fhdr associative array
   }
}
!seen[$1]++ {                   # if this id is not found in seen array
   keys[++k] = $1               # store in seen and in keys array by index
}
{
   for (i=2; i<=NF; ++i)        # for each field starting from 2nd column
      map[$1][i] = map[$1][i] (map[$1][i] == "" ? "" : OFS) (FNR == 1 ? fhdr[ARGIND] : "") $i
   # build 2 dimensional array map where key is $1,i and value is column  value
   # for 1st record prefix column value with part filename stored in fhdr array
   # we keep appending value in this array with OFS delimiter
}
END {                           # do this in the end
   for (i=2; i<=NF; ++i) {      # for each column position from 2 onwards
      for (j=1; j<=k; j++) {    # for each id stored in keys array 
         key = keys[j]
         print key, map[key][i] # print id and value text built above
      }
      print ""                  # print a line break
   }
}

【讨论】:

  • 我已经添加了详细的解释。
  • 我可以假设我发布的代码不容易for循环,因此需要重新编写它吗?我喜欢你的代码,我正在剖析它以更好地理解它。问题 - 如果输入文件 f{A,B,C} 具有以下格式,需要进行哪些更改才能使代码正常工作?即前 3 行包含文件信息(仅在所需的输出文件中保留一次),第 4 行的列标题)第 1 行:通用数据。第 2 行:第 3 行编译:光谱耗散 id fA_V fB_F fC_L
  • 如果文件名只是 f{A,B,C} 和它们的 .txt 扩展名,那么首先在内部使用 fhdr[i] = ARGV[i] "_" for loop for (i=1; i&lt;=ARGC; ++i) 并去掉里面的 3 行。
猜你喜欢
  • 1970-01-01
  • 2016-11-25
  • 2020-09-18
  • 1970-01-01
  • 1970-01-01
  • 2016-05-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多