1行以内の桁数を数えてファイルを分割する方法は?

1行以内の桁数を数えてファイルを分割する方法は?

1行に45000文字を含むファイルがあり、行内の特定の文字数に基づいて元のファイルを分割したいと思います。小さな例として、入力ファイルは次のようになります。

入力.txt:

123394531112334455938383726644600000111234499922281133
234442221117273747474747474729292921111098887777772235
231112233647474838389292121037549284753930837475111013

各行には54桁の数字があります。最初の10桁は別々のファイルで、11~24桁は別のファイルにしたいと思います。ビット25〜32は別のファイルであり、ビット33〜50は最後のファイルです。例:

out1.txt(1-10)

1233945311
2344422211
2311122336

out2.txt(11-24)

 12334455938383
 17273747474747
 47474838389292

out3.txt(25-32)

72664460
47472929
12103754

out4.txt(33-54)

0000111234499922281133
2921111098887777772235
9284753930837475111013

どんな提案がありますか?

答え1

cut複数回呼び出すことができます。

cut -c 1-10  < file > out1.txt
cut -c 11-24 < file > out2.txt
cut -c 25-32 < file > out3.txt
cut -c 33-54 < file > out4.txt

(現在のバージョンのGNUはcutマルチバイト文字をサポートしていません(入力のASC​​II 10進数には問題ありません)。

またはawkため息で:

awk '{
  print substr($0, 1,  10) > "out1.txt"
  print substr($0, 11, 14) > "out2.txt"
  print substr($0, 25, 8 ) > "out3.txt"
  print substr($0, 33, 22) > "out4.txt"}' < file

awk(現在のバージョンの一部の実装はmawkマルチバイト文字をサポートしていません(ASCII 10進数では問題ありません)。)

GNUを使用すると、awk次のこともできます。

awk -v FIELDWIDTHS='10 14 8 22' '
  {for (i = 1; i <= NF; i++) print $i > "out" i ".txt"}' < file

答え2

読み取りとパラメータの置換/拡張/分割を使用して、Bashを使用してこれを実行できます。形式は ${PARAMETER:OFFSET:LENGTH} で、ここで OFFSET は 0 から始まります。たとえば、次のファイルを「split」として保存し、次のように各行を読み取ります。

#!/usr/bin/env bash

# Usage: ./split "data.txt"

while IFS= read -r line
do
    printf '%s\n' "${line:0:10}"  >&3  #  1-10
    printf '%s\n' "${line:10:14}" >&4  # 11-24
    printf '%s\n' "${line:24:8}"  >&5  # 25-32
    printf '%s\n' "${line:32:22}" >&6  # 33-54
done < "$1" 3> output01.txt 4> output02.txt 5> output03.txt 6> output04.txt

# end file

もちろん、上記の場所を少し調整する必要があるかもしれませんが、このモデルはさまざまな種類のファイル処理に使用できます。 上記の位置は所望の出力を生成する。パラメータ拡張のための良い参考資料は次のとおりです。bash-hackers.org


PostScriptとして推奨される改善点(説明を参照)を組み込んだ後、大容量ファイルの場合、BashアプローチはCPU時間とCPUリソースの面では効率的ではないことに注意してください。この声明を数量化するために、以下に簡単な比較を準備しました。まず、開始記事データの長さが300,000行(16500000バイト)のテストファイル(bigsplit.txt)を作成します。それから比較分ける切るそしてアッの中切るそしてアッ実装は同じですスティーブン・チャジェラスバージョン。秒単位のCPU時間はシステムとユーザーのCPU時間の合計であり、RAMは使用された最大値です。

$ stat -c %s bigsplit.txt && wc -l bigsplit.txt 
16500000
300000 bigsplit.txt

$ ./benchmark ./split bigsplit.txt 

CPU TIME AND RESOURCE USAGE OF './split bigsplit.txt'
VALUES ARE THE AVERAGE OF ( 10 ) TRIALS

CPU, sec :   88.41
CPU, pct :   99.00
RAM, kb  : 1494.40

$ ./benchmark ./cut bigsplit.txt 

CPU TIME AND RESOURCE USAGE OF './cut bigsplit.txt'
VALUES ARE THE AVERAGE OF ( 10 ) TRIALS

CPU, sec :    0.86
CPU, pct :   99.00
RAM, kb  :  683.60

$ ./benchmark ./awk bigsplit.txt

CPU TIME AND RESOURCE USAGE OF './awk bigsplit.txt'
VALUES ARE THE AVERAGE OF ( 10 ) TRIALS

CPU, sec :    1.19
CPU, pct :   99.00
RAM, kb  : 1215.60

比較は次のとおりです。最高のパフォーマンス、切るには値1が割り当てられます。

                             RELATIVE PERFORMANCE 

                                    CPU Secs     RAM kb
                                    --------     ------
                    cut                    1          1
                    awk                  1.4        1.8
                    split (Bash)       102.8        2.2

この場合、疑いの余地はありません。切る大きなファイルのためのツールです。 Bashのおおよその予備テスト分ける上に、ファイルから読み込むときループにはCPU時間が約5秒かかりました。パラメータ拡張約8秒ほどかかり、残りはと関連があると言えます。ファイルとしてprintf操作。

関連情報