Como cortar uma lima em pedaços com mais eficiência?

Como cortar uma lima em pedaços com mais eficiência?

Suponha que eu tenha um arquivo de texto de 10 MB foo.txte 100.000 linhas. Agora, quero processar foo.txtjanela por janela, com janela de tamanho 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?

Responder1

Você pode fazer isso com split:

Aqui está um exemplo de como usá-lo:

split -l 10 input_file output_file_prefix_

A -lopção significa--lines=

E isso será dividido input_fileem pedaços com 10 linhas cada, nestes arquivos:

output_file_prefix_aa
output_file_prefix_ab
output_file_prefix_ac
...

e assim por diante.

Para outras maneiras que você pode usar split, veja man splitouaqui

Responder2

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 o Precision.sh?

De qualquer forma, se você quiser continuar usando o bash, você pode 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

Responder3

Não sei por que isso foi migrado do StackOverflow. Enquanto splité umsuperusuárioresposta estilo, a pergunta era sobre programação. Por exemplo, aqui está uma resposta que implementa o que você está procurando no awk.

Um dos aspectos realmente úteis awké a maneira como ele lida com tubos.

#!/usr/bin/awk -f

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

{
  print | cmd
}

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

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

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

Estritamente falando, você não precisa usar uma variável como cmdpara armazenar o comando ... mas torna mais simples ajustar o comando, já que caso contrário você precisaria observar MUITO cuidadosamente se há erros de digitação no seu arquivo close().

Responder4

Esta solução não usa arquivos temporários. O que isso faz é armazenar cada linha em uma matriz de buffer que pode conter dez linhas. Cada vez que o número da linha é divisível por dez, ele imprime todas as linhas do 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:

$ eco {1..33} | tr\\n |\
    awk '{linhas=NR} END{ if (linhas%10!=0) { imprimir "linhas restantes"} }'
linhas restantes

# STEP1 usa módulo para fazer algo a cada décimo
$ echo {1..200} |tr \ \\n |\
    awk '{a[NR%10]=$0; if (NR%10==0) {print "dez"} }' | gato -n
     1 dez
     2 dez
     3 dez
     4 dez
     5 dez
     6 dez
     7 dez
     8 dez
     9 dez
    10 dez
    11 dez
    12 dez
    13 dez
    14 dez
    15 dez
    16 dez
    17 dez
    18 dez
    19 dez
    20 dez

# PASSO 2 faça algo com cada linha
$ eco {1..10} | tr\\n | awk '{b+=$0} END {imprimir b}'
55

# Juntar as peças
$ gato a cada 10.awk
{
        a[NR%10]=$0;
        if (NR%10==0) {
                para (eu em a) {
                        printf "%s+", a[i]
                        b+=uma[i];
                }
                imprima "0="b;
                b=0
        }
}
$ eco {1..200} | tr\\n | awk -f cada10.awk | coluna -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 ideia aqui é usar awk print blocos de dez linhas e processá-los, ou processar diretamente com awk se a operação for simples aritmética ou operações de string.

informação relacionada