根据列将文件拆分为多个文件的最有效方法

时间:2018-11-16 19:05:17

标签: linux bash unix awk split

一段时间以来,我一直在寻找一种有效地执行此操作的方法,但始终无法提出最佳解决方案。

要求很简单。我有以下格式的文件。

$cat mymainfile
rec1,345,field3,....field20
rec1,645,field3,....field20
rec12,345,field3,....field20
frec23,45,field3,....field20
rec34,645,field3,....field20

在拆分操作结束时,我想拥有多个具有这些名称的单独文件

$cat some_prefix_345_some_suffix_date
rec1,345,field3,....field20
rec12,345,field3,....field20

$cat some_prefix_645_some_suffix_date
rec1,645,field3,....field20
rec34,645,field3,....field20

$cat some_prefix_45_some_suffix_date
frec23,45,field3,....field20

我考虑过使用grep,但是它必须先找到唯一的ID,然后再为每个grep查找grep,因为在读取mymainfile之前我们不知道文件中的ID(345,645等)。

然后我想到了csplit,例如在这里Split one file into multiple files based on delimiter,但它是基于定界符而不是特定列进行拆分的。

关于bash脚本编写,我知道我可以使用while loop逐行阅读并将其拆分,但不知道这样做是否有效。

我还想到了awk之类的awk '$2 == ? {解决方案,但不知道如何获取这些不同的文件名。我可以使用python以编程方式进行操作,但更喜欢使用单个命令行,并且我知道这是可能的。我已经厌倦了搜索,但是仍然找不到最佳的方法。任何建议/最佳方法将不胜感激。

2 个答案:

答案 0 :(得分:8)

在awk内,您可以将每行的输出重定向到您动态创建名称的另一个文件(在这种情况下,基于$2

$ awk -F, '{print > ("some_prefix_" $2 "_some_suffix_date")}' file

$ ls *_date
some_prefix_345_some_suffix_date    some_prefix_45_some_suffix_date     some_prefix_645_some_suffix_date

$ cat some_prefix_345_some_suffix_date 
rec1,345,field3,....field20
rec12,345,field3,....field20

$ cat some_prefix_645_some_suffix_date 
rec1,645,field3,....field20
rec34,645,field3,....field20

$ cat some_prefix_45_some_suffix_date 
frec23,45,field3,....field20

如注释中所指出的,如果$2的值很多,并且打开文件过多而出错,则可以随时关闭:

 $ awk -F, '{fname = "xsome_prefix_" $2 "_some_suffix_date"
             if (a[fname]++) print >> fname; else print > fname;
             close fname}' file

答案 1 :(得分:2)

我可能会比awk慢,但我将从

开始
cat mymainfile |  cut -d, -f2 | sort -u

获得所需的其他第二个值。 然后使用egrep进行循环,并使用gnu parallel加快速度:

cat mymainfile |  cut -d, -f2 | sort -u | parallel 'egrep "[^,]+,{}," mymainfile  > some_prefix_{}_some_suffix_date'

{}在并行命令中扩展为不同的值。 egrep“ [^,] +,{}”之后的正则表达式应仅与第二列中的值匹配。

由于这两个循环,并希望使用不断增长的文件:

cat mymainfile | parallel 'echo {} >> some_prefix_$(echo {} | cut -d\, -f2)_some_suffix_date'

不幸的是,这调用了一个子外壳,使其速度变慢。只需尝试一下。