我有一个包含两列的 test1.csv 文件
group,email
[email protected],[email protected]
[email protected],[email protected]
[email protected],[email protected]
[email protected],[email protected]
[email protected],[email protected]
[email protected],[email protected]
[email protected],[email protected]
[email protected],[email protected]
[email protected],[email protected]
我的目标是根据第一列的值创建单独的文本文件。
例如:
第一个文件名为[电子邮件受保护]并含有
[email protected]
[email protected]
[email protected]
[email protected]
第一个文件名为[电子邮件受保护]并含有
[email protected]
[email protected]
等等。
我有这个 awk 命令
awk -F"," 'NR==1{header=$0}NR>2&&!a[$1]++{print header > (""$1"")}NR>2{print > (""$1"")}' test1.csv
但结果并不是我真正想要的,尽管文件的命名是正确的:
group,email
[email protected],[email protected]
[email protected],[email protected]
[email protected],[email protected]
每当 .csv 文件太大时,我也会收到“Awk:打开文件太多”的消息
任何帮助表示赞赏。还研究不同的语言,例如 sed 或 grep
答案1
这就是您所需要的:
awk -F ',' 'NR<2{next} p1!=$1&&p1{close(p1)} {p1=$1;print $2>p1}' file
NR<2{next}
: 跳过标题。p1!=$1&&p1{close(p1)}
:当上一行 (p1
) 的第一个字段与当前行的第一个字段不同时,前一个输出文件将被关闭,这样您就不会得到“太多打开的文件”(除非尚未打开任何文件并且正在p1
打开)。未设置)。{p1=$1;print $2>p1}
:将第一个字段放入p1
变量中,并将第二个字段打印到具有第一个字段名称的文件中。
请注意,上面的 awk 假设具有相同第一个字段的行在 中分组在一起file
,如提供的示例所示。如果不是这种情况,一个简单的解决方案是向 awk 提供排序的输入,显式跳过标头(因为标头不再位于第一行):
sort file | awk -F ',' '/^group,email$/{next} p1!=$1&&p1{close(p1)} {p1=$1;print $2>p1}'
答案2
您可以直接awk
重定向到(域名应该是空格安全的)中给出的文件名$2
$1
awk -F, 'NR>1{print $2 > $1}' file
尽管这会跳过标头并使文件保持打开状态。您可以通过测试这是否是一个++h[$1]==1
要写入>
标头的新文件来修复此问题,然后>>
使用追加$2
close($1)
awk -F, '
NR==1{header=$0}
NR>1{
if(++h[$1]==1)print header > $1;
print $2 >> $1; close ($1)
}' file
为了避免重复,只需++f[$0]==1
在附加之前进行测试。
awk -F, '
NR==1{header=$0}
NR>1&&++f[$0]==1{
if(++h[$1]==1)print header > $1;
print $2 >> $1; close ($1)
}' file
head *.com
==> [email protected] <==
group,email
[email protected]
[email protected]
[email protected]
[email protected]
==> [email protected] <==
group,email
[email protected]
[email protected]
==> [email protected] <==
group,email
[email protected]
[email protected]
[email protected]
如果您的文件已全部或部分排序,那么您可以通过以下方式避免盲目打开和关闭每一行
awk -F, '
NR==1{header=$0}
NR>1&&++f[$0]==1{
if ($1 != old) close(old);
if(++h[$1]==1)print header > $1;
print $2 >> $1; old=$1
}' file
因为这使用数据文件中$2 >>
是否有第二块并不重要$1
,它不会被新的删除>
答案3
使用米勒(https://github.com/johnkerl/miller) 简单来说就是
mlr --csv put -q 'tee > $group, $*' ./input.csv
mlr -I --c2n cut -f email ./group*@*
这不是 awk,但我认为它可能对你有用
答案4
$ awk '{print (NR>1),$0}' file | sort -k1,1n -k2 | cut -d' ' -f2- |
awk -F, '
NR==1 { hdr=$0; next }
$1 != out { close(out); out=$1; print hdr > out }
{ print $2 " > " out }
'
上面的代码可以使用任何 awk 来处理几乎任何大小的输入文件,并且输入行以任何顺序排列,而且速度很快。
更改print $2 " > " out
为print $2 > out
完成测试后实际生成输出文件。