使用 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)
}

相關內容