Разделить файл на 10 файлов с уникальным элементом в каждом файле и максимальным лимитом числа строк в каждом файле

У меня огромный файл (более 2 миллионов записей в нем). Вот мое требование:

  • Сначала разбить один большой файл на 10 файлов меньшего размера.
  • Файлы должны быть отформатированы следующим образом: <File_name><timestamp>xx
    • <timestamp> – одно и то же время в каждом файле
    • xx будет представлять файл с 1 по 10
  • Файлы должны иметь чистое разделение между элементами. То есть мы не можем иметь один и тот же элемент в нескольких файлах.

Например, если у меня есть файл, как показано ниже:

 ITEM,PARENT_PARTNUMBER,STORE_NUMBER,QUANTITY,BUYABLE,AVAILABILITYCODE,STORENAME,PHONENUMBER 400000209333,400000209333P,ALL,1297,1,2,, 400000209333,400000209333P,A-80007838,1297,1,2,, 400009664058,400009664058P,ALL,499,1,1,, 400009664058,400009664058P,A-80007838,477,1,1,, 400009664058,400009664058P,13806529,104,0,0,WDW - FLOWER & GARDEN,8-224-6122/5866 400000276151,400000276151P,ALL,0,0,0,, 400000276151,400000276151P,A-80007823,0,0,0,, 400000209692,400000209692P,ALL,8,1,1,, 

Затем я хочу разбить файлы так. Первый файл (предположим, что первый файл достиг предела 20000, а в 19999 – изменение номера элемента, которое не может находиться в одном файле из-за максимального ограничения файла как 20000, и нам нужно сохранить уникальный номер элемента в файле:

 400000209333,400000209333P,ALL,1297,1,2,, 400000209333,400000209333P,A-80007838,1297,1,2,, 400009664058,400009664058P,ALL,499,1,1,, 400009664058,400009664058P,A-80007838,477,1,1,, 400009664058,400009664058P,13806529,104,0,0,WDW - FLOWER & GARDEN,8-224-6122/5866 

Второй файл:

 400000276151,400000276151P,ALL,0,0,0,, 400000276151,400000276151P,A-80007823,0,0,0,, 400000209692,400000209692P,ALL,8,1,1,, 

и так далее до файла 10.

2 Solutions collect form web for “Разделить файл на 10 файлов с уникальным элементом в каждом файле и максимальным лимитом числа строк в каждом файле”

 #!/bin/bash file_name="huge.file" #get file mask my_mask="$(date +"$file_name-%F-")" #collect lines with same item in one string separated by unexpected symbol sed ':1;N;/^\([^,]\+,\).*\n\1/s/\n/×/;t1;P;D' "$file_name" > tmp.file #divide tmp.file for 10 pieces without line splitting split -dn l/10 "tmp.file" "$my_mask" #split lines with same item back sed -i 's/×/\n/g' "$my_mask"* #remove tmp.file if need it rm tmp.file 

Окончательная версия, клянусь … 🙂

Предполагается, что:

  • первая строка содержит заголовок,
  • ПУНКТ всегда является первым столбцом,
  • все линии с одинаковым номером ITEM являются последовательными,
  • количество строк с таким же номером ITEM меньше, чем количество строк в каждом меньшем файле минус 1.

Эта версия гарантирует, что файлы меньшего размера будут содержать несколько строк, меньших или равных указанному верхнему пределу (например, LINES ).

 #!/usr/bin/awk -f BEGIN { numberOfLinesInCurrentFile=0; numberOfLinesInBuffer=0; filenumber=0; header=""; previousITEM=""; FS=","; timestamp=ENVIRON["TIMESTAMP"]; numberOfLinesPerFile=ENVIRON["LINES"]; currentFilename=FILENAME "-" timestamp "-00"; } { if (NR == 1) { header=$0; print header >> currentFilename; numberOfLinesInCurrentFile=1; } else { currentITEM=$1; if (previousITEM != currentITEM) { for (i=0; i<numberOfLinesInBuffer; i++) { print bufferOfLines[i] >> currentFilename; } numberOfLinesInCurrentFile+=numberOfLinesInBuffer; numberOfLinesInBuffer=0; bufferOfLines[1]=$0 } if ((numberOfLinesInCurrentFile+numberOfLinesInBuffer) >= numberOfLinesPerFile) { filenumber++; currentFilename=sprintf("%s-%s-%02d", FILENAME, timestamp, filenumber); print header >> currentFilename; numberOfLinesInCurrentFile=1; } bufferOfLines[numberOfLinesInBuffer++]=$0 previousITEM=$1; } } 

LINES используется для указания максимального количества строк на меньшие файлы.

TIMESTAMP используется для указания метки времени.

bigfile – это файл для разделения.

Ниже приведен тест:

 LINES=4000 TIMESTAMP=20160320101538 ./scriptv2.awk bigfile ls bigfile* bigfile bigfile-20160320101538-02 bigfile-20160320101538-04 bigfile-20160320101538-06 bigfile-20160320101538-08 bigfile-20160320101538-01 bigfile-20160320101538-03 bigfile-20160320101538-05 bigfile-20160320101538-07 

—-


ВТОРАЯ ВЕРСИЯ ДЛЯ СПРАВОЧНИКА: она не гарантирует, что количество строк в каждом меньшем файле будет находиться под указанным пределом.

Еще одна версия быстро протестирована. Предполагается, что первая строка содержит заголовок и что ITEM всегда является первым столбцом. Все линии с одинаковым номером ITEM являются последовательными.

 cat script.awk #!/usr/bin/awk -f BEGIN { filenumber=0; header=""; previousITEM=""; FS=","; timestamp=ENVIRON["TIMESTAMP"]; numberOfLinesPerFile=ENVIRON["LINES"]; currentFilename=FILENAME "-" timestamp "-00"; changeFilenameWhenPossible=0; } { if (NR == 1) { header=$0; } else { currentITEM=$1; if (NR % numberOfLinesPerFile == 0) { if (previousITEM != currentITEM) { filenumber=filenumber+1; filenamberString=sprintf("%02d",filenumber); currentFilename=FILENAME "-" timestamp "-" filenamberString; changeFilenameWhenPossible=0; print header >> currentFilename; } else { changeFilenameWhenPossible=1; } } else if (changeFilenameWhenPossible == 1 && previousITEM != currentITEM) { filenumber=filenumber+1; filenamberString=sprintf("%02d",filenumber); currentFilename=FILENAME "-" timestamp "-" filenamberString; changeFilenameWhenPossible=0; print header >> currentFilename; } previousITEM=$1; } print $0 >> currentFilename; } 

LINES должен быть установлен на количество строк, требуемых для меньших файлов.

TIMESTAMP должен быть установлен на отметку времени.

bigfile – это файл 2M строк.

Ниже приведен тест:

 chmod +x script.awk LINES=200000 TIMESTAMP=20160318101538 ./script.awk bigfile ls -1 bigfile-* bigfile-20160318101538-01 bigfile-20160318101538-02 bigfile-20160318101538-03 bigfile-20160318101538-04 bigfile-20160318101538-05 bigfile-20160318101538-06 bigfile-20160318101538-07 bigfile-20160318101538-08 bigfile-20160318101538-09 bigfile-20160318101538-10 

Для справки первый ответ …

Я заметил, что вы хотите избавиться от самой первой строки с заголовком, не так ли?

 #!/bin/bash -- nblines=$(wc -l "${1}" | cut -d\ -f1) nblines=$(((nblines - 1)/10)) tail -n +2 "${1}" | split -l $nblines -d -- - "${1}"-"${2}"- touch -r "${1}" ./"${1}"?* 

Обязательно проверьте файл bigfile, который содержит 11 строк и более.

Команда touch используется для применения времени большого файла ко всем более мелким, только что созданным. Удалите касание, если оно не понадобится.

новое редактирование еще не протестировано:

 ls bigfile script.sh chmod +x ./script.sh ./script.sh bigfile 20160309144430 ls -l bigfile* -rw-r--r-- 1 jay stackgrp 556 Mar 16 17:03 bigfile -rw-r--r-- 1 jay stackgrp 92 Mar 16 17:03 bigfile-20160309144430-00 -rw-r--r-- 1 jay stackgrp 42 Mar 16 17:03 bigfile-20160309144430-01 

и т.п.

Обратите внимание, что ls показывает одно и то же время для всех bigfile * благодаря команде touch .

Interesting Posts
Linux и Unix - лучшая ОС в мире.