ファイルをより効率的に分割するにはどうすればよいでしょうか?

ファイルをより効率的に分割するにはどうすればよいでしょうか?

10MB のテキスト ファイルがありfoo.txt、その内容が 100,000 行あるとします。ここで、foo.txtウィンドウ サイズを 10 にして、ウィンドウごとに処理したいと考えています。

私の現在のスクリプトは次のようになります:

for ((i=0;i<$lines;i=i+$step))
do    
    head -$((i+step)) $1 | tail -$step > tmp1
    head -$((i+step)) $2 | tail -$step > tmp2
    setstr=$setstr' '`./accuracy.sh tmp1 tmp2`
done
echo $setstr | awk '{for (i=1;i<=NF;i++) sum+=$i; }END{print sum/NF}'

しかし、動作が遅いです。これを行うための簡単で効率的な方法はあるでしょうか?

答え1

それは次のようにして実行できますsplit:

使用方法の例を次に示します。

split -l 10 input_file output_file_prefix_

オプション-l--lines=

そして、これはinput_file10 行ずつのチャンクに分割され、次のファイルに出力されます。

output_file_prefix_aa
output_file_prefix_ab
output_file_prefix_ac
...

等々。

の他の使い方についてはsplitman splitまたはを参照してください。ここ

答え2

コード スニペットではなく、最終的な目標に関するコンテキストをもう少し詳しく教えていただけると助かります。特に、accuracy.sh を制御できますか?

とにかく、bashを使い続けたいのであれば、次のようにすればよい。

for ((i=0;i<$lines;i+=$step))
do
  let end=i+10
  sed -n $i,${end}p $1 >tmp1
  sed -n $i,${end}p $2 >tmp2
  ...
done

答え3

splitなぜこれがStackOverflowから移行されたのかは分かりません。スーパーユーザースタイルの回答の場合、質問はプログラミングに関するものでした。たとえば、以下は で探しているものを実装する回答ですawk

の本当に便利な点の 1 つは、awkパイプの処理方法です。

#!/usr/bin/awk -f

BEGIN {
  cmd="/path/to/handler"
}

{
  print | cmd
}

NR % 10 == 0 {
  close(cmd)
}

閉じられている場合は再度開かcmdれます... 10 行ごとに閉じられ、出力の次の行で再度開かれます。

効果は、handler入力の 10 行ごとに実行されることです。ファイルの最後では、handler残っている行が実行され、cmdawk が終了すると自動的に閉じられます。

厳密に言えば、コマンドを保存するために のような変数を使用する必要はありませんcmd...ただし、 内のタイプミスを非常に注意深く監視する必要があるため、コマンドの調整が簡単になりますclose()

答え4

このソリューションでは、一時ファイルは使用されません。10 行を保持できるバッファー配列に各行を保存します。行番号が 10 で割り切れるたびに、バッファー内のすべての行が出力されます。

明らかな落とし穴は、入力ファイル (行数) が 10 で割り切れない場合です。解決策は、END{} 句でチェックすることです。次のようになります。

$ エコー {1..33} | tr \ \\n |\
    awk '{lines=NR} END{ if (lines%10!=0) { print "残りの行"} }'
残った線

# STEP1 剰余を使って10分ごとに何かを行う
$ エコー {1..200} |tr \ \\n |\
    awk '{a[NR%10]=$0; if (NR%10==0) {print "ten"} }' | cat -n
     1 10
     2 10
     3 10
     4 10
     5 10
     6 10
     7 10
     8 10 ...
     9 10 9月
    10 10
    11 10
    12 10
    13 10
    14 10
    15 10
    16 10
    17 10
    18 10
    19 10
    20 10

# ステップ 2 各行で何かを行う
$ echo {1..10} | tr \ \\n | awk '{ b+=$0} END {print b}'
55

# それを一緒に入れて
$ 猫 every10.awk
{
        [NR%10] = $0;
        (NR%10==0)の場合{
                (i in a) の場合 {
                        printf "%s+", a[i]
                        b+=a[i];
                }
                "0=" を印刷します。b;
                0 です
        }
}
$ echo {1..200} | tr \ \\n | awk -f every10.awk | 列 -s= -t
4+5+6+7+8+9+10+1+2+3+0 55
14+15+16+17+18+19+20+11+12+13+0 155
24+25+26+27+28+29+30+21+22+23+0 255
34+35+36+37+38+39+40+31+32+33+0 355
44+45+46+47+48+49+50+41+42+43+0 455
54+55+56+57+58+59+60+51+52+53+0 555
64+65+66+67+68+69+70+61+62+63+0 655
74+75+76+77+78+79+80+71+72+73+0 755
84+85+86+87+88+89+90+81+82+83+0 855
94+95+96+97+98+99+100+91+92+93+0 955
104+105+106+107+108+109+110+101+102+103+0 1055
114+115+116+117+118+119+120+111+112+113+0 1155
124+125+126+127+128+129+130+121+122+123+0 1255
134+135+136+137+138+139+140+131+132+133+0 1355
144+145+146+147+148+149+150+141+142+143+0 1455
154+155+156+157+158+159+160+151+152+153+0 1555
164+165+166+167+168+169+170+161+162+163+0 1655
174+175+176+177+178+179+180+171+172+173+0 1755
184+185+186+187+188+189+190+181+182+183+0 1855
194+195+196+197+198+199+200+191+192+193+0 1955

ここでの考え方は、awk を使用して 10 行のブロックを印刷し、それを処理するか、操作が単純な算術演算または文字列演算である場合は awk で直接処理することです。

関連情報