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;}"'
pattern
une expression régulière ou un modèle de coque plus simple?