2017-01-03 5 views
1

大きな(〜870,000,000行)テキストファイルから特定のグループの行を引き出すことを検討しています。たとえば、50行のファイルでは、3〜6行、18〜27行、39〜45行が必要です。大きなテキストファイルから行のグループを読み取る

スタックオーバーフローを閲覧から、私はbashコマンドことを発見した:

tail -n+NUMstart file |head -nNUMend 

がNUMstartから始まり、NUMendに行くラインの単一の行またはグループを取得するための最速の方法です。しかし、複数のグループの行を読むときは、これは非効率的です。通常、この手法はそれほど重要ではありませんが、ファイルが大きければ大きな違いになります。

上記のコマンドを各行のグループに使用するよりも良い方法がありますか?私はその答えがおそらくbashコマンドになると仮定していますが、仕事を最も良くする言語/ツールには本当にオープンしています。

答えて

3

ライン3-6を表示するには、18-27と39-45:

sed -n "3,6p;18,27p;39,45p" file 

それからSED供給することも可能ですファイル。ファイルfoobar

内容:

 
3,6p 
18,27p 
39,45p 

使用法:救助へ

sed -n -f foobar file 
+0

これは 'awk'よりもはるかに速いのか不思議です。 – codeforester

+1

これはファイル全体をスキャンし、最後の行の後ろにあるexitを使って 'awk'より速くすることはできません。 – karakfa

+2

最後のコマンドとして '45q'を追加するとそれが修正されます。 –

0

異なる範囲のtail -n XX file | head -n YYの問題は、それを数回実行していることです。したがって、非効率です。それ以外の場合は、benchmarksが最適な解決策であることを示します。あなたのケースでは

awk '(NR>=start1 && NR<=end1) || (NR>=start2 && NR<=end2) || ...' file 

:この特定のケースでは

は、あなたが awk使用することをお勧めします、あなたのグループの範囲としましょう awkプリント対応するラインである

awk '(NR>=3 && NR<=6) || (NR>=18 && NR<=27) || (NR>=39 && NR<=45)' file 

をするとき、彼ら一度ファイルをループするだけです。また、最後の興味深い行を読み終えたら処理を終了するように、最後のNR==endX {exit}(最後の範囲の終了項目であるendX)を追加すると便利です。あなたのケースでは

SEDと
awk '(NR>=3 && NR<=6) || (NR>=18 && NR<=27) || (NR>=39 && NR<=45); NR==45 {exit}' file 
1

awk

awk -v lines='3-6,18-27,39-45' ' 
     BEGIN {n=split(lines,a,","); 
       for(i=1;i<=n;i++) 
       {split(a[i],t,"-"); 
       rs[++c]=t[1]; re[c]=t[2]}} 

      {for(i=s;i<=c;i++) 
       if(NR>=rs[i] && NR<=re[i]) {print; next} 
       else if(NR>re[i]) s++; 
       if(s>c) exit}' file 

は、最後に印刷された行の後に早期に終了します。エラーチェックを行わない場合は、範囲を昇順に指定する必要があります。

+0

良いアプローチ。しかし、私はレンジフィードがここでは特に問題ではないと思うので、 'BEGIN'ブロックは何とか(私にとって)無関係です。 – fedorqui

関連する問題