Предположим, у меня есть текстовый файл размером 10 МБ 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
Не уверен, почему это перенесли со StackOverflow. Пока split
этосуперпользователь-стиль ответа, вопрос был о программировании. Например, вот ответ, который реализует то, что вы ищете в awk
.
Одним из действительно удобных аспектов 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
Это решение не использует временные файлы. Оно сохраняет каждую строку в буферном массиве, который может содержать десять строк. Каждый раз, когда номер строки делится на десять, оно печатает все строки в буфере.
Очевидная ловушка — когда входной файл (# строк) не делится на десять. Решение — сделать проверки в предложении END{}. Что-то вроде:
$ echo {1..33} | tr \ \\n |\ awk '{lines=NR} END{ if (lines%10!=0) { print "оставшиеся строки"} }' оставшиеся линии # ШАГ1 использовать остаток от деления на десятые, чтобы сделать что-то $ echo {1..200} |tr \ \\n |\ awk '{a[NR%10]=$0; если (NR%10==0) {напечатать "десять"} }' | cat -n 1 десяток 2 десятка 3 десятка 4 десять 5 десять 6 десять 7 десять 8 десять 9 десять 10 десять 11 десять 12 десять 13 десять 14 десять 15 десять 16 десять 17 десять 18 десять 19 десять 20 десять # ШАГ 2 сделайте что-нибудь с каждой строкой $ echo {1..10} | tr \ \\n | awk '{ b+=$0} END {print b}' 55 # собираем все вместе $ cat каждые10.awk { а[NR%10]=$0; если (НР%10==0) { для (i в а) { printf "%s+", а[i] б+=а[я]; } распечатать "0=" б; б=0 } } $ echo {1..200} | tr \ \\n | awk -f every10.awk | column -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 для печати блоков по десять строк и обрабатывать их, или обрабатывать напрямую с помощью awk, если операция представляет собой простую арифметику или строковые операции.