Como cortar um arquivo em pedaços com mais eficiência?

4

Suponha que eu tenha um arquivo de texto de 10 MB foo.txt e tenha 100.000 linhas. Agora, eu quero processar foo.txt janela por janela, com um tamanho de janela 10.

Meu script atual é assim:

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}'

Mas corre devagar. Existe alguma maneira simples e mais eficiente de fazer isso?

    
por JackWM 10.11.2012 / 22:03

4 respostas

5

Você pode fazer isso com split :

Veja um exemplo de como usá-lo:

split -l 10 input_file output_file_prefix_

A opção -l representa --lines=

E isso dividirá input_file em blocos com 10 linhas cada nesses arquivos:

output_file_prefix_aa
output_file_prefix_ab
output_file_prefix_ac
...

e assim por diante.

Para outras formas, você pode usar split , consulte man split ou aqui

    
por 10.11.2012 / 22:10
1

Seria útil ter um pouco mais de contexto quanto ao seu objetivo final, em vez de um trecho de código. Em particular, você tem algum controle sobre precisão.sh?

De qualquer forma, se você quiser continuar usando o bash, então você poderia fazer

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
    
por 14.11.2012 / 07:50
0

Não sei por que isso foi migrado do StackOverflow. Embora split seja uma resposta em estilo superusuário , a questão era sobre programação. Por exemplo, aqui está uma resposta que implementa o que você está procurando em awk .

Um dos aspectos realmente úteis de awk é o modo como ele lida com tubos.

#!/usr/bin/awk -f

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

{
  print | cmd
}

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

Seu cmd será reaberto se estiver fechado ... e será fechado a cada 10 linhas, para reabertura da próxima linha de saída.

O efeito será executar handler a cada 10 linhas de entrada. No final do arquivo, handler será executado com as linhas restantes, pois cmd é automaticamente fechado quando o awk sai.

Estritamente falando, você não precisa usar uma variável como cmd para armazenar o comando ... mas simplifica o ajuste do comando, já que de outra forma você precisaria observar MUITO com cuidado quanto a erros de digitação. seu close() .

    
por 11.11.2012 / 18:36
0

Esta solução não usa arquivos temporários. O que é que é armazenar todas as linhas em uma matriz de buffer que pode conter dez linhas. Toda vez que o número da linha é divisível por dez, ele imprime todas as linhas no buffer.

A armadilha óbvia é quando o arquivo de entrada (# linhas) não é divisível por dez. A solução é fazer verificações em uma cláusula END {}. Algo como:

$ echo {1..33} | tr \  \n |\
    awk '{lines=NR} END{ if (lines%10!=0) { print "leftover lines"} }'
leftover lines

# STEP1 use modulo to do something every tenth
$ echo {1..200} |tr \  \n |\
    awk '{a[NR%10]=$0; if (NR%10==0) {print "ten"} }' | cat -n
     1  ten
     2  ten
     3  ten
     4  ten
     5  ten
     6  ten
     7  ten
     8  ten
     9  ten
    10  ten
    11  ten
    12  ten
    13  ten
    14  ten
    15  ten
    16  ten
    17  ten
    18  ten
    19  ten
    20  ten

# STEP 2 do something with every line
$ echo {1..10} | tr \  \n | awk '{ b+=$0} END {print b}'
55

# putting it together
$ cat every10.awk
{
        a[NR%10]=$0;
        if (NR%10==0) {
                for (i in a) {
                        printf "%s+", a[i]
                        b+=a[i];
                }
                print "0=" b;
                b=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

A idéia aqui é usar blocos de dez linhas no awk print e processá-los, ou processar com o awk diretamente se a operação for simples operações aritméticas ou de string.

    
por 19.11.2012 / 06:23