bashでは、任意のバイトカウントオフセットからファイルの読み取りを開始できますか?


22

8 GBログ(テキスト)のどこかにある日付を見つけたい。

完全な順次読み取りをいくらかバイパスし、最初にファイルのバイナリ分割(サイズ)を行うか、何らかの方法でファイルシステムをナビゲートしinodes(これについてはほとんど知りません)、適切なオフセットが見つかるまで各分割ポイントから読み取りを開始できますか?日付を含む行のテキスト検索を開始する場所

tailの最後の行の読み取りは通常の順次読み取りを使用しないため、この機能が何らかの方法でbashで利用できるのか、PythonまたはC / C ++を使用する必要があるのでしょうか...しかし、私は特にbashオプションに興味があります..


回答:


8
for (( block = 0; block < 16; block += 1 ))
do 
    echo $block; 
    dd if=INPUTFILE skip=$((block*512))MB bs=64 count=1 status=noxfer 2> /dev/null | \
        head -n 1
done

which ..は、一時分割ファイルを作成せず、実行ごとにブロック* 512MBのデータをスキップし、その位置から64バイトを読み取り、出力をその64バイトの最初の行に制限します。

64を必要に応じて調整することができます。


@akira ..これは本当によさそうですが、最初にもう少し見たいと思います..(
つまり

1
@akira ..「dd」はすごい。バイナリ分割検索でうまく機能します...ソートされた8Gファイルから正規表現された行を(日付キーで)1秒未満で抽出できるようになりました... 2つのキー(包括的)間の日付範囲を抽出するための2番目の個人ターゲット。出力時間を除きます。出力時間は、出力される量によって異なります。私も使用ddします。:)
Peter.O

30

あなたが望むように聞こえます:

tail -c +1048576

またはスキップしたいバイト数。プラス記号は、末尾ではなくファイルの先頭から測定するようにtailに指示します。GNUバージョンのtailを使用している場合、次のように記述できます。

tail -c +1M

ファイルの残りすべての代わりに、カット後に固定バイト数を取得するには、単に先頭にパイプします:

tail -c +1048576 | head -c 1024

Linux / bashの柔軟性はすごいです(Linuxへの切り替えには長い時間がかかりました)。私はアキラの答えを受け入れたところですが、これをより完全に評価するまでそれを引きました。dd特定のバイトにジャンプします(同様にtail)が、未知の行の長さをコード化するのに苦労し、その後sedを呼び出して先頭の部分的な行を削除します... tail | headは痛みなく(高速で) 。私は頭が尾のタップをオフにする方法を理解していませんが、それは次のように思われます:頭が受信を停止すると、尾は送信を停止します(そしてさらに読むことを停止します)。行かなければならない。明日戻って。
Peter.O

@ fred.bear:tail/ head行の長さを盲目的に推測することもできません。あなたは位置xにジャンプしなければならないので、次のためにxの左または右を見ることができます\n。プログラムの名前は関係ありません。そのため、どちらの場合もxにジャンプしてからhead、次の行末を右に見るために使用します。
アキラ

tail|head心配することはないの申し出能力をまったくについてddのカウント数=ヴァル。「dd」では、十分なデータを取得しないと、「ゲームオーバー」になります。任意のライン長の柔軟性は素晴らしいです。「次の最も近い」フルラインとそのオフセットを返す「dd」用の関数を作成しましたが、長さの問題は避けたいと思います。私は今tail | headをテストしましたが、最初はうまく機能します(オフセット= 100MBまで)が、オフセット= 8GBで1回のアクセスに2分かかると劇的に遅くなります(awk1分でできます)...以下のための小さなファイルの..テール/ヘッドコンボの私を認識させるためのおかげで:)
Peter.O

2

このようなことを試して、ログを512MiBのチャンクに分割して、解析を高速化します。

split <filename> -b 536870912

ファイルを探している場合、次のように動作します。

for file in x* ; do
  echo $file
  head -n 1 $file
done

その出力を使用して、日付に対してgrepするファイルを決定します。


感謝しますが、順次検索よりも時間がかかります。ここに私のコメントを見てくださいunix.stackexchange.com/questions/8121/…(ここで同じことを書き直すのではなく)
-Peter.O

'split'を使用すると、1バイトごとに1回タッチします。そうすれば、8GB全体をgrepすることもできます。
アキラ

@sifusam ..(ファイルを分割するだけでなく)バイナリ分割検索を行いたいen.wikipedia.org/wiki/Binary_search_algorithm ... 異なる 質問に対する良い回答でした:) ..回答ありがとうございます。 +1してあなたを転がします....
Peter.O

0

ここに私のスクリプトがあります。最初のフィールドが私の番号と一致する最初の行を探しています。行は最初のフィールドに従ってソートされます。ddを使用して128Kのブロックの最初の行を確認し、ブロックにジャンプして検索を実行します。ファイルが1Mを超えると、効率が向上します。

コメントや修正を歓迎します!

#!/bin/bash

search=$1;
f=$2;

bs=128;

max=$( echo $(du $f | cut -f1)" / $bs" | bc );
block=$max;
for i in $(seq 0 $max); do
 n=$(dd bs=${bs}K skip=$i if=$f 2> /dev/null| head -2 | tail -1 | cut -f1)
 if [ $n -gt $search ]; then
  block=`expr $i - 1` 
  break;
 fi
done; 
dd bs=${bs}K skip=$block if=$f 2> /dev/null| tail -n +2 | awk -v search="$search" '$1==search{print;exit 1;};$1>search{exit 1;};';

*編集* ** grepははるかに高速で、 ackはさらに優れています

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.