파일을 각 파일에 고유한 항목이 포함된 10개의 파일로 분할하고 각 파일의 최대 줄 수를 제한합니다.

파일을 각 파일에 고유한 항목이 포함된 10개의 파일로 분할하고 각 파일의 최대 줄 수를 제한합니다.

나는 거대한 파일(200만개 이상의 레코드)을 가지고 있습니다. 이것은 내 요구 사항입니다.

  • 먼저 큰 파일을 10개의 작은 파일로 분할합니다.
  • 파일 형식은 다음과 같아야 합니다. <File_name>- <timestamp>-xx
    • <timestamp>각 파일의 동일한 시간
    • xx1부터 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

등.

알아채다엘에스모든 대용량 파일*을 동시에 표시합니다. 감사합니다.만지다주문하다.

관련 정보