Em geral, usar o shell para análise de texto é muito lento e complicado. Aqui estão algumas outras opções:
-
Perl no "modo de parágrafo"
perl -00pe 's/^/$./' file
Explicação
O -00
ativa o modo de parágrafo onde "linhas" são definidas por \n\n
consecutivos, parágrafos em outras palavras. O s/^/$./
substituirá o início da linha ( ^
) pela atual "linha" (parágrafo) número $.
. O -p
diz ao perl para imprimir cada linha do arquivo de entrada depois de executar o script fornecido por -e
sobre ele.
-
Awk
awk -vRS='\n\n' -vORS='\n\n' '{print NR$0}' file
Explicação
-vRS='\n\n'
define o separador de registros do awk para caracteres consecutivos de nova linha. Como o modo de parágrafo do perl, isso faz com que ele trate os parágrafos como "linhas". Em seguida, informamos para imprimir o número da linha atual ( NR
) e a "linha" atual $0
. O -vORS=
define o separador de registro de saída como novas linhas consecutivas, de forma que os parágrafos também sejam separados por linhas em branco na saída. Observe que isso adicionará 2 linhas vazias no final da saída. Para evitar isso, você pode usar head
:
awk -v RS='\n\n' -vORS='\n\n' '{print NR$0}' file | head -n -2
Por meio de comparação, aqui estão os horários que as várias soluções tomaram no meu sistema quando executadas em um arquivo de teste de 10M:
$ time a.sh > /dev/null ## a.sh is Cyrus's solution
real 0m1.419s
user 0m1.308s
sys 0m0.104s
$ time perl -00pe 's/^/$./' file > /dev/null
real 0m0.087s
user 0m0.084s
sys 0m0.000s
$ time awk -v RS='\n\n' -vORS='\n\n' '{print NR$0}' file | head -n -2 >/dev/null
real 0m0.074s
user 0m0.056s
sys 0m0.020s
Como você pode ver acima, as soluções perl e awk são uma ordem de magnitude mais rápida que a abordagem shell.