使用 awk 逐行连接七个文件

使用 awk 逐行连接七个文件

我有七个(或八个等等)行数相同的文件。

文件1

1.001
1.002
1.003
1.004

文件2

2.001
2.002
2.003
2.004

文件3

3.001
3.002
3.003
3.004

ETC。

期望的输出:

1.001;2.001;3.001;4.001;5.001;6.001;7.001
1.002;2.002;3.002;4.002;5.002;6.002;7.002
1.003;2.003;3.003;4.003;5.003;6.003;7.003
1.004;2.004;3.004;4.004;5.004;6.004;7.004

如何在 awk 中使用简短的脚本来做到这一点?

答案1

正如 Steeldriver 所说,做到这一点的合理方法是paste

$ paste -d';' file*
1.001;2.001;3.001;4.001;5.001;6.001;7.001;8.001
1.002;2.002;3.002;4.002;5.002;6.002;7.002;8.002
1.003;2.003;3.003;4.003;5.003;6.003;7.003;8.003
1.004;2.004;3.004;4.004;5.004;6.004;7.004;8.004

但是,如果您必须使用awk

$ awk '{a[FNR]=a[FNR](FNR==NR?"":";")$0} END{for (i=1;i<=FNR;i++) print a[i]}' file*
1.001;2.001;3.001;4.001;5.001;6.001;7.001;8.001
1.002;2.002;3.002;4.002;5.002;6.002;7.002;8.002
1.003;2.003;3.003;4.003;5.003;6.003;7.003;8.003
1.004;2.004;3.004;4.004;5.004;6.004;7.004;8.004

awk 脚本将所有数据保存在内存中。如果文件很大,这可能是一个问题。但是,对于这个任务来说,paste无论如何都更好、更简单。

怎么运行的

在此脚本中,a有一个数组,它a[i]是 line 的输出i。当我们阅读每个后续文件时,我们将 line 的新信息附加ia[i].读取完文件后,我们打印出 中的值a。更详细地说:

  • a[FNR]=a[FNR](FNR==NR?"":";")$0

    FNR是我们正在读取的当前文件的行号,$0是该行的内容。这段代码添加$0到 的末尾a[FNR]。除非我们仍在读取第一个文件,否则我们会在 之前添加一个分号$0。这是使用看起来复杂的三元语句来完成的:(FNR==NR?"":";")。这实际上只是一个 if-then-else 命令。如果我们正在读取第一个文件,即 if FNR==NR,那么它返回一个空字符串""。如果不是,则返回一个分号;

  • END{for (i=1;i<=FNR;i++) print a[i]}

    当我们读完所有文件后,这会打印出我们在 array 中积累的数据a

答案2

POSIX awk;这适用于任意数量的文件,并且文件甚至不必具有相同数量的行。该脚本将继续运行,直到所有文件都超出行数:

BEGIN {
  do {
    br = ch = 0
    while (++ch < ARGC)
      if (getline < ARGV[ch]) {
        printf ch < ARGC - 1 ? $0 ";" : $0 RS
        br = 1
      }
  } while (br)
}

相关内容