Как эффективнее разрезать файл на куски?
Предположим, у меня есть текстовый файл 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()
,