나는 거대한 파일(200만개 이상의 레코드)을 가지고 있습니다. 이것은 내 요구 사항입니다.
- 먼저 큰 파일을 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까지 계속됩니다.
답변1
#!/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
답변2
최종 버전입니다. 맹세합니다...:)
가정:
- 첫 번째 줄에는 제목이 포함되어 있습니다.
- ITEM은 항상 첫 번째 열입니다.
- 동일한 ITEM 번호를 가진 모든 행은 연속적이며,
- 동일한 ITEM 번호를 가진 행 수는 각 작은 파일의 행 수에서 1을 뺀 수보다 적습니다.
이 버전에서는 더 작은 파일에 지정된 상한값 이하의 행 수가 포함되도록 보장합니다(예:선).
#!/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=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;
}
선더 작은 파일당 원하는 줄 수로 설정해야 합니다.
타임스탬프지정된 타임스탬프로 설정되어야 합니다.
대용량 파일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}"?*
꼭 이용해주세요대용량 파일11줄 이상을 포함합니다.
이것만지다적용 시간 명령대용량 파일방금 만든 모든 작은 것들에. 제거하다만지다필요하지 않은 경우.
아직 테스트되지 않은 새로운 편집 내용:
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
등.
알아채다엘에스모든 대용량 파일*을 동시에 표시합니다. 감사합니다.만지다주문하다.