Awk

將 CSV 數據過濾到多個單獨的文件中

  • May 18, 2020

我有一個名為的 CSV 文件file1.csv

something;AD;sss;Andorra;nothing;type_1;sss
something222;AD;sss222;Andorra;nothing222;type_2;aaa
thing;NL;thing3;Netherlands;thing;type_2;bb
etc;US;etc;United States;etc;type_2;nothing

我想為每個國家/地區創建單獨的文件。我做這樣的greps:

grep -e "\;AD\;.*\;Andorra\;" file1.csv > fileAD.csv
grep -e "\;NL\;.*\;Netherlands\;" file1.csv > fileNL.csv
grep -e "\;US\;.*\;United\sStates\;" file1.csv > fileUS.csv

這行得通,但我有世界上所有國家,我不想為每個國家寫這些行。還有其他解決方案嗎?

我還有一個帶有type_1and的專欄type_2。我需要考慮到這一點。在創建了每個國家對應的所有文件之後,我需要為每個國家創建新文件 justtype_1和新文件 just type_2

例如,對於安道爾,我需要以下文件:

  • fileAD.csv:
something;AD;sss;Andorra;nothing;type_1;sss
something222;AD;sss222;Andorra;nothing222;type_2;aaa
  • fileADtype_1.csv:
something;AD;sss;Andorra;nothing;type_1;sss
  • fileADtype_2.csv:
something222;AD;sss222;Andorra;nothing222;type_2;aaa

我認為只查找帶有縮寫的列是可以的,但是出於安全原因,我想要兩列,一列AD帶有全名,另一列帶有全名。Andorra

假設數據是簡單的CSV 數據,即沒有欄位包含嵌入的分隔符或換行符:

awk -F ';' '
   {
       print > "file" $2    ".csv"
       print > "file" $2 $6 ".csv"
   }' file1.csv

這將每行列印兩次,一次列印到僅由第二個欄位的值給出的文件,一次列印到由第二個和第六個欄位的值組合給出的文件。根據問題中的文本,每個輸出文件名都將以字元串為前綴並以字元串為file後綴。.csv

不對文件名中使用的兩個欄位的值進行驗證。

如果要合併第四個欄位中的國家/地區名稱:

awk -F ';' '
   {
       print > "file_" $2 "-" $4        ".csv"
       print > "file_" $2 "-" $4 "_" $6 ".csv"
   }' file1.csv

對於給定的數據,這將創建以下文件

file_AD-Andorra.csv
file_AD-Andorra_type_1.csv
file_AD-Andorra_type_2.csv
file_NL-Netherlands.csv
file_NL-Netherlands_type_2.csv
file_US-United States.csv
file_US-United States_type_2.csv

以上在使用 GNU 的系統上執行良好awk。其他awk實現可能會遇到同時打開太多文件以供寫入的問題。在這樣awk的實現中,您必須更聰明,並記住在寫入文件後關閉文件。關閉文件後,必須記住>>在下次將數據寫入文件時列印,否則文件將被截斷。

awk -F ';' '
   function do_print(name) {
       if (seen[name] == 1) print >>name  # append to file
       else                 print  >name  # first write, truncate file
       close(name)
       seen[name] = 1
   }
   {
       do_print("file_" $2 "-" $4        ".csv")
       do_print("file_" $2 "-" $4 "_" $6 ".csv")
   }' file1.csv

這也將使程式碼可以awk在 OpenBSD 上使用,而您不能使用它print >來處理表達式。


額外(只是為了好玩):使awk程式碼輸出一些統計數據:

awk -F ';' '
   function do_print(name) {
       if (seen[name] > 0) print >>name  # append to file
       else                print  >name  # first write, truncate file
       close(name)
       seen[name]++
   }
   {
       do_print("file_" $2 "-" $4        ".csv")
       do_print("file_" $2 "-" $4 "_" $6 ".csv")
   }
   END {
       for (name in seen)
           printf "Wrote %d lines to \"%s\"\n", seen[name], name >"/dev/stderr"
   }' file1.csv

這會在處理結束時將一些統計資訊寫入錯誤流。對於給定的數據:

Wrote 1 lines to "file_NL-Netherlands.csv"
Wrote 1 lines to "file_US-United States_type_2.csv"
Wrote 1 lines to "file_AD-Andorra_type_1.csv"
Wrote 2 lines to "file_AD-Andorra.csv"
Wrote 1 lines to "file_NL-Netherlands_type_2.csv"
Wrote 1 lines to "file_US-United States.csv"
Wrote 1 lines to "file_AD-Andorra_type_2.csv"

引用自:https://unix.stackexchange.com/questions/587457