Awk
將 CSV 數據過濾到多個單獨的文件中
我有一個名為的 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_1
and的專欄type_2
。我需要考慮到這一點。在創建了每個國家對應的所有文件之後,我需要為每個國家創建新文件 justtype_1
和新文件 justtype_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"