(AWK) Csv 将列中的相同变量分离到不同的文件中

(AWK) Csv 将列中的相同变量分离到不同的文件中

我有一个包含两列的 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要写入>标头的新文件来修复此问题,然后>>使用追加$2close($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 " > " outprint $2 > out完成测试后实际生成输出文件。

相关内容