Самый эффективный способ разбить файл на несколько файлов на основе столбца - PullRequest
0 голосов
/ 16 ноября 2018

Я уже некоторое время ищу способ сделать это эффективно и не могу найти лучшего решения.

Требование простое. У меня есть файл следующего формата.

$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, но он должен найти уникальные идентификаторы, а затем grep для каждого, поскольку мы не знаем идентификаторы (345 645 и т. Д.), Которые находятся в файле до чтения mymainfile.

Затем я подумал о csplit, например, вот здесь Разделить один файл на несколько файлов на основе разделителя , но он разделяется на основе разделителя, а не на конкретный столбец.

Когда дело доходит до сценариев bash, я знаю, что могу читать построчно, используя while loop, и разбивать его, но не знаю, будет ли он эффективным.

Я также думал о awk решениях, таких как awk '$2 == ? { и т. Д., Но не знаю, как получить эти разные имена файлов. Я могу сделать это программно, используя python, но предпочитаю одну командную строку, и я знаю, что это возможно. Я устал от поиска и до сих пор не могу найти лучший подход для этого, хотя. Любые предложения / лучший подход будет принята с благодарностью.

Ответы [ 2 ]

0 голосов
/ 16 ноября 2018

Это может быть медленнее, чем awk, но я бы начал с

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

, чтобы получить другое необходимое вам второе значение.Затем создайте цикл с egrep и используйте gnu параллельно, чтобы ускорить его:

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'

к сожалению, это вызывает подоболочку, которая замедляет работу.Просто попробуйте.

0 голосов
/ 16 ноября 2018

В 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
...