Angenommen, ich habe eine 10 MB große Textdatei foo.txt
mit 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 -l
Option steht für--lines=
Und dies wird input_file
in 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 split
finden Sie unter man split
oderHier
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 split
es 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 awk
ist 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 cmd
wird 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 handler
alle 10 Eingabezeilen ausgeführt wird. Am Ende der Datei handler
wird mit den verbleibenden Zeilen ausgeführt und cmd
automatisch 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.