我有一个名为的 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
我想为每个国家/地区创建单独的文件。我这样制作 grep:
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
和 的专栏type_2
。我需要考虑到这一点。创建了每个国家/地区对应的所有文件后,我需要为每个国家/地区创建新文件,type_1
并使用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
答案1
假设数据是简单的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"