ファイルを各ファイルに固有のエントリを含む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

2番目のファイル:

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

----


メモ用の2番目のバージョン:各小さなファイルの行数が指定された制限より小さいことを保証しません。

別のバージョンが迅速にテストされました。最初の行にヘッダーが含まれており、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

など。

気づくエルエスすべての大容量ファイル*を同時に表示します。ありがとうございます。触れる注文する。

関連情報