Daher tendiere ich im Allgemeinen dazu, nach sed
Textverarbeitung zu suchen - insbesondere nach großen Dateien - und vermeide es normalerweise, solche Dinge in der Shell selbst zu tun.
Ich denke jedoch, dass sich das ändern kann. Ich stöberte herum man ksh
und bemerkte Folgendes:
<#pattern Seeks forward to the beginning of the
next line containing pattern.
<##pattern The same as <# except that the por‐
tion of the file that is skipped is
copied to standard output.
Ich war skeptisch gegenüber der Nützlichkeit der realen Welt und beschloss, es auszuprobieren. Ich tat:
seq -s'foo bar
' 1000000 >file
... für eine Million Datenzeilen, die aussehen wie:
1foo bar
...
999999foo bar
1000000
... und stellte es gegen sed
wie:
p='^[^0-8]99999.*bar'
for c in "sed '/$p/q'" "ksh -c ':<##@(~(E)$p)'"
do </tmp/file eval "time ( $c )"
done | wc -l
Daher sollten beide Befehle bis zu 999999foo bar erhalten, und ihre Implementierung für den Mustervergleich muss mindestens den Anfang und das Ende jeder Zeile auswerten, um dies zu tun. Sie müssen auch das erste Zeichen anhand eines negierten Musters überprüfen. Dies ist eine einfache Sache, aber ... Die Ergebnisse waren nicht das, was ich erwartet hatte:
( sed '/^[^0-8]99999.*bar/q' ) \
0.40s user 0.01s system 99% cpu 0.419 total
( ksh -c ':<##@(~(E)^[^0-8]99999.*bar)' ) \
0.02s user 0.01s system 91% cpu 0.033 total
1999997
ksh
verwendet hier ERE und sed
ein BRE. Ich habe das gleiche mit ksh
und einem Shell-Muster gemacht, aber die Ergebnisse unterschieden sich nicht.
Wie auch immer, das ist eine ziemlich bedeutende Diskrepanz - ksh
übertrifft das sed
Zehnfache. Ich habe vorher gelesen, dass David Korn seine eigene io lib geschrieben und implementiert hat ksh
- möglicherweise hängt das damit zusammen? - aber ich weiß so gut wie nichts darüber. Wie kommt es, dass die Shell das so gut macht?
Noch erstaunlicher für mich ist, dass ksh
der Versatz wirklich genau dort bleibt, wo Sie ihn fragen. Um (fast) dasselbe aus (GNU) herauszuholen sed
, muss man verwenden -u
- sehr langsam .
Hier ist ein grep
v. ksh
Test:
1000000 #grep + head
( grep -qm1 '^[^0-8]99999.*bar'; head -n1; ) \
0.02s user 0.00s system 90% cpu 0.026 total
999999foo bar #ksh + head
( ksh -c ':<#@(~(E)^[^0-8]99999.*bar)'; head -n1; ) \
0.02s user 0.00s system 73% cpu 0.023 total
ksh
Beats grep
hier - aber nicht immer - sie sind ziemlich gebunden. Trotzdem ist das ziemlich gut und ksh
bietet Lookahead - head
die Eingabe beginnt vor dem Match.
Es scheint einfach zu schön, um wahr zu sein, denke ich. Was machen diese Befehle unter der Haube anders?
Oh, und anscheinend gibt es hier nicht einmal eine Unterschale:
ksh -c 'printf %.5s "${<file;}"'
quelle
pattern
ein regulärer Ausdruck oder ein einfacheres Shell-Muster?Antworten:
Ksh verwendet nicht nur sfio, sondern auch einen eigenen benutzerdefinierten Speicherzuweiser.
Trotzdem denke ich, dass sfio in diesem Fall den Unterschied macht. Ich habe gerade versucht, Ihr Beispiel unter Strace auszuführen, und kann sehen, dass ksh-Aufrufe ~ 200-mal (65-KB-Blöcke) lesen / schreiben, während sed ~ 3400-mal (4-KB-Blöcke) ausführt. Mit sed -u ist mein Laptop fast geschmolzen, Lesevorgänge erfolgen pro Byte und Schreibvorgänge pro Zeile. Ksh simple verwendet lseek. Grep verwendet ~ 400-mal Lesen (32-KB-Blöcke).
quelle
ksh
die Regex-Engine als Io effizient ist. Trotzdem vielen Dank für die Antwort. Ich entschuldige mich bei Ihrem Laptop. Was ist jedoch mit dem benutzerdefinierten Speicherzuweiser? Hast du noch mehr dazu?