Как эффективнее разрезать файл на куски?
Предположим, у меня есть текстовый файл 10 МБ foo.txtи имеет 100000 строк. Теперь я хочу обработать 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}'
Но это работает медленно. Есть ли простой и более эффективный способ сделать это?
4 ответа
Вы можете сделать это с 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 или здесь
Было бы полезно иметь немного больше контекста относительно вашей конечной цели, а не фрагмент кода. В частности, есть ли у вас контроль над precision.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
Это решение не использует никаких временных файлов. Что делает, так это хранит каждую строку в буферном массиве, который может содержать десять строк. Каждый раз, когда номер строки делится на десять, он печатает все строки в буфере.
Очевидная ошибка, когда входной файл (# строк) не делится на десять. Решение состоит в том, чтобы сделать проверки в предложении END{}. Что-то вроде:
$ echo {1..33} | tr \ \\ n | \
awk '{lines = NR} END {if (lines% 10! = 0) {вывести "оставшиеся строки"} }'
оставшиеся линии
# ШАГ1 использовать по модулю, чтобы сделать что-то каждую десятую
$ echo {1..200} |tr \ \\n |\
awk '{a[NR%10]=$0; if (NR%10==0) {print "ten"} }' | кот-н
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 every10.awk
{
а [NR% 10] = $ 0;
если (NR% 10 == 0) {
для (я в) {
printf "%s+", a[i]
Ь += а [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 для печати блоков из десяти строк и обрабатывать их, или обрабатывать непосредственно с помощью awk, если операция является простой арифметической или строковой операцией.
Не уверен, почему это было перенесено из 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(),