¿Cómo cortar una lima en pedazos de manera más eficiente?

¿Cómo cortar una lima en pedazos de manera más eficiente?

Supongamos que tengo un archivo de texto de 10 MB foo.txty tiene 100.000 líneas. Ahora quiero procesar foo.txtventana por ventana, con un tamaño de ventana 10.

Mi script actual es así:

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

Pero va lento. ¿Existe alguna forma sencilla y más eficiente de hacer esto?

Respuesta1

Puedes hacer eso con split:

A continuación se muestra un ejemplo de cómo utilizarlo:

split -l 10 input_file output_file_prefix_

La -lopción significa--lines=

Y esto se dividirá input_fileen fragmentos de 10 líneas cada uno, en estos archivos:

output_file_prefix_aa
output_file_prefix_ab
output_file_prefix_ac
...

etcétera.

Para conocer otras formas en las que puede utilizar split, consulte man splitoaquí

Respuesta2

Sería útil tener un poco más de contexto sobre su objetivo final en lugar de un fragmento de código. En particular, ¿tiene algún control sobre precision.sh?

De todos modos, si quieres seguir usando bash, entonces puedes hacer

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

Respuesta3

No estoy seguro de por qué se migró desde StackOverflow. mientras splites unsuperusuarioRespuesta de estilo, la pregunta era sobre programación. Por ejemplo, aquí hay una respuesta que implementa lo que estás buscando en awk.

Uno de los aspectos realmente útiles awkes la forma en que maneja las tuberías.

#!/usr/bin/awk -f

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

{
  print | cmd
}

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

Se cmdvolverá a abrir si está cerrado... y se cierra cada décima línea, para volver a abrirse en la siguiente línea de salida.

El efecto será ejecutar handlercada 10 líneas de entrada. Al final del archivo, handlerse ejecutará con las líneas que queden, y cmdse cerrará automáticamente cuando awk salga.

Estrictamente hablando, no necesita usar una variable como cmdpara almacenar el comando... pero hace que sea más sencillo ajustar el comando, ya que de lo contrario necesitaría observar MUY cuidadosamente para detectar errores tipográficos en su archivo close().

Respuesta4

Esta solución no utiliza ningún archivo temporal. Lo que hace es almacenar cada línea en una matriz de búfer que puede contener diez líneas. Cada vez que el número de línea es divisible por diez, imprime todas las líneas en el búfer.

El problema obvio es cuando el archivo de entrada (# líneas) no es divisible por diez. La solución es realizar comprobaciones en una cláusula END{}. Algo como:

$ eco {1..33} | tr\\\n |\
    awk '{lines=NR} END{ if (lines%10!=0) { print "líneas sobrantes"} }'
líneas sobrantes

# PASO 1 usa el módulo para hacer algo cada diez
$ eco {1..200} |tr \ \\n |\
    awk '{a[NR%10]=$0; if (NR%10==0) {imprimir "diez"} }' | gato -n
     1 diez
     2 diez
     3 diez
     4 diez
     5 diez
     6 diez
     7 diez
     8 diez
     9 diez
    10 diez
    11 diez
    12 diez
    13 diez
    14 diez
    15 diez
    16 diez
    17 diez
    18 diez
    19 diez
    20 diez

# PASO 2 haz algo con cada línea
$ eco {1..10} | tr\\\n | awk '{ b+=$0} FIN {imprimir b}'
55

# Poniendo todo junto
$ gato cada 10.awk
{
        a[NR%10]=$0;
        si (NR%10==0) {
                para (yo en a) {
                        printf "%s+", a[yo]
                        b+=a[i];
                }
                imprimir "0="b;
                b=0
        }
}
$ eco {1..200} | tr\\\n | awk -f cada10.awk | columna -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

La idea aquí es utilizar awk imprimir bloques de diez líneas y procesarlos, o procesar con awk directamente si la operación es aritmética simple o operaciones de cadena.

información relacionada