Wie schneidet man eine Datei effizienter in Stücke?

Wie schneidet man eine Datei effizienter in Stücke?

Angenommen, ich habe eine 10 MB große Textdatei foo.txtmit 100.000 Zeilen. Nun möchte ich sie Fenster für Fenster verarbeiten foo.txt, mit einer Fenstergröße von 10.

Mein aktuelles Skript sieht folgendermaßen aus:

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

Aber es läuft langsam. Gibt es eine einfachere und effizientere Möglichkeit, dies zu tun?

Antwort1

Das geht mit split:

Hier ist ein Anwendungsbeispiel:

split -l 10 input_file output_file_prefix_

Die -lOption steht für--lines=

Und dies wird input_filein Blöcke mit jeweils 10 Zeilen in diese Dateien aufgeteilt:

output_file_prefix_aa
output_file_prefix_ab
output_file_prefix_ac
...

und so weiter.

Weitere Verwendungsmöglichkeiten splitfinden Sie unter man splitoderHier

Antwort2

Es wäre nützlich, etwas mehr Kontext zu Ihrem Endziel zu haben als einen Codeausschnitt. Haben Sie insbesondere irgendeine Kontrolle über precision.sh?

Wenn Sie weiterhin Bash verwenden möchten, können Sie Folgendes tun:

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

Antwort3

Ich bin mir nicht sicher, warum dies von StackOverflow migriert wurde. Während splites einSuperuser-Stil-Antwort, die Frage bezog sich auf Programmierung. Hier ist beispielsweise eine Antwort, die das, was Sie suchen, in implementiert awk.

Einer der wirklich praktischen Aspekte awkist die Art und Weise, wie es mit Rohren umgeht.

#!/usr/bin/awk -f

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

{
  print | cmd
}

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

Ihr cmdwird erneut geöffnet, wenn es geschlossen ist ... und wird jede 10. Zeile geschlossen, um in der nächsten Ausgabezeile erneut geöffnet zu werden.

Der Effekt besteht darin, dass handleralle 10 Eingabezeilen ausgeführt wird. Am Ende der Datei handlerwird mit den verbleibenden Zeilen ausgeführt und cmdautomatisch geschlossen, wenn awk beendet wird.

Streng genommen müssen Sie zum Speichern des Befehls keine Variable wie verwenden cmd… aber es vereinfacht die Anpassung des Befehls, da Sie sonst SEHR sorgfältig auf Tippfehler in Ihrer achten müssten close().

Antwort4

Diese Lösung verwendet keine temporären Dateien. Sie speichert jede Zeile in einem Pufferarray, das zehn Zeilen aufnehmen kann. Immer wenn die Zeilennummer durch zehn teilbar ist, werden alle Zeilen im Puffer gedruckt.

Die offensichtliche Falle ist, wenn die Eingabedatei (Anzahl der Zeilen) nicht durch zehn teilbar ist. Die Lösung besteht darin, Prüfungen in einer END{}-Klausel vorzunehmen. So etwas wie:

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

# SCHRITT1 Verwenden Sie Modulo, um jedes Zehntel etwas zu tun
$ echo {1..200} |tr \ \\n |\
    awk '{a[NR%10]=$0; wenn (NR%10==0) {print "zehn"} }' | cat -n
     1 Zehner
     2 zehn
     3 zehn
     4 zehn
     5 zehn
     6 zehn
     7 zehn
     8 zehn
     9 zehn
    10 zehn
    11 zehn
    12 zehn
    13 zehn
    14 zehn
    15 zehn
    16 zehn
    17 zehn
    18 zehn
    19 zehn
    20 zehn

# SCHRITT 2 Mach etwas mit jeder Zeile
$ echo {1..10} | tr \ \\n | awk '{ b+=$0} END {print b}'
55

# etwas zusammensetzen
$ Katze alle 10.awk
{
        a[NR%10]=$0;
        wenn (NR%10==0) {
                für (i in a) {
                        printf "%s+", a[i]
                        b+=a[i];
                }
                drucke "0=" b;
                b=0
        }
}
$ echo {1..200} | tr \ \\n | awk -f every10.awk | Spalte -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

Die Idee besteht hier darin, mit awk Blöcke von zehn Zeilen zu drucken und diese zu verarbeiten, oder direkt mit awk zu verarbeiten, wenn es sich bei der Operation um einfache Arithmetik- oder Zeichenfolgenoperationen handelt.

verwandte Informationen