Assim, em geral, tenho a tendência de olhar para sed
para processamento de texto - especialmente para arquivos grandes - e geralmente evito fazer esse tipo de coisa no próprio shell.
Eu acho que isso pode mudar. Eu estava bisbilhotando em man ksh
e notei isso:
<#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.
Cético quanto à utilidade do mundo real, decidi experimentá-lo. Eu fiz:
seq -s'foo bar
' 1000000 >file
... para um milhão de linhas de dados que se parecem com:
1foo bar
...
999999foo bar
1000000
... e colocou contra sed
como:
p='^[^0-8]99999.*bar'
for c in "sed '/$p/q'" "ksh -c ':<##@(~(E)$p)'"
do </tmp/file eval "time ( $c )"
done | wc -l
Assim, ambos os comandos devem chegar a 999999foo bar e sua implementação de correspondência de padrões deve avaliar pelo menos o início e o fim de cada linha para fazer isso. Eles também precisam verificar o primeiro caractere contra um padrão negado. Isso é uma coisa simples, mas ...
Os resultados não foram o que eu esperava:
( 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
usa ERE aqui e sed
a BRE. Eu fiz a mesma coisa com ksh
e um padrão de shell antes, mas os resultados não diferiram.
De qualquer forma, essa é uma discrepância bastante significativa - ksh
supera sed
10 vezes. Eu já li antes que David Korn escreveu seu próprio io lib e o implementa em ksh
- possivelmente isso está relacionado? - mas eu não sei quase nada sobre isso. Como é que a casca faz isso tão bem?
Ainda mais surpreendente para mim é que ksh
realmente deixa seu deslocamento exatamente onde você pergunta. Para obter (quase) o mesmo de (GNU) sed
, você tem que usar -u
- muito lento .
Veja um teste 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
bate grep
aqui - mas nem sempre - eles estão praticamente empatados. Ainda assim, isso é muito bom, e ksh
fornece lookahead - a entrada de head
é iniciada antes de sua correspondência.
Parece bom demais para ser verdade, eu acho. Quais são esses comandos fazendo diferente sob o capô?
Ah, e aparentemente não há nem mesmo uma subshell aqui:
ksh -c 'printf %.5s "${<file;}"'