Donc, en général, j'ai tendance à rechercher le sed
traitement de texte - en particulier pour les gros fichiers - et à éviter généralement de faire ce genre de choses dans le shell lui-même.
Je pense cependant que cela pourrait changer. Je fouinais man ksh
et j'ai remarqué ceci:
<#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.
Sceptique quant à son utilité dans le monde réel, j'ai décidé de l'essayer. J'ai fait:
seq -s'foo bar
' 1000000 >file
... pour un million de lignes de données qui ressemblent à:
1foo bar
...
999999foo bar
1000000
... et l'a opposé sed
comme:
p='^[^0-8]99999.*bar'
for c in "sed '/$p/q'" "ksh -c ':<##@(~(E)$p)'"
do </tmp/file eval "time ( $c )"
done | wc -l
Ainsi, les deux commandes doivent obtenir jusqu'à 999999foo bar et leur implémentation de correspondance de modèle doit évaluer au moins le début et la fin de chaque ligne pour ce faire. Ils doivent également vérifier le premier caractère par rapport à un modèle annulé. C'est une chose simple, mais ... Les résultats n'étaient pas ce à quoi je m'attendais:
( 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
utilise ERE ici et sed
un BRE. J'ai fait la même chose avec ksh
un motif de coque auparavant, mais les résultats ne différaient pas.
Quoi qu'il en soit, c'est un écart assez important - ksh
surpasse sed
10 fois. J'ai lu auparavant que David Korn a écrit son propre io lib et l'implémente dans ksh
- peut-être que cela est lié? - mais je n'en sais presque rien. Comment se fait-il que la coquille le fasse si bien?
Encore plus étonnant pour moi, c'est que ksh
cela laisse vraiment son décalage là où vous le demandez. Pour obtenir (presque) la même chose de (GNU), sed
vous devez utiliser -u
- très lentement .
Voici un test grep
v ksh
:
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
bat grep
ici - mais pas toujours - ils sont à peu près liés. Pourtant, c'est assez excellent, et ksh
fournit une entrée anticipée - head
commence avant son match.
Cela semble trop beau pour être vrai, je suppose. Que font ces commandes différemment sous le capot?
Oh, et apparemment il n'y a même pas de sous-shell ici:
ksh -c 'printf %.5s "${<file;}"'
la source
pattern
une expression régulière ou un modèle de coque plus simple?Réponses:
Non seulement ksh utilise sfio, mais il utilise son propre allocateur de mémoire personnalisé.
Néanmoins, je suppose que sfio fait la différence dans ce cas. J'ai juste essayé d'exécuter votre exemple sous strace et je peux voir que ksh appelle en lecture / écriture ~ 200 fois (blocs de 65 Ko) tandis que sed le fait ~ 3400 fois (blocs de 4 Ko). Avec sed -u mon ordinateur portable a presque fondu, les lectures se font par octet et les écritures par ligne. Ksh simple utilise lseek. Grep utilise lecture ~ 400 fois (blocs de 32 Ko).
la source
ksh
le moteur regex est aussi efficace que son io? Quoi qu'il en soit, merci beaucoup pour la réponse. Mes excuses à votre ordinateur portable. Mais qu'en est-il de l'allocateur de mémoire personnalisé? En avez-vous d'autres à ce sujet?