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_file
10 行ずつのチャンクに分割され、次のファイルに出力されます。
output_file_prefix_aa
output_file_prefix_ab
output_file_prefix_ac
...
等々。
の他の使い方についてはsplit
、man 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
残っている行が実行され、cmd
awk が終了すると自動的に閉じられます。
厳密に言えば、コマンドを保存するために のような変数を使用する必要はありません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 で直接処理することです。