grep -n | sort | sed | cut
( export LC_ALL=C
grep -n '' | sort -t: -nmk1,1 ./L - |
sed /:/d\;n | cut -sd: -f2-
) <./F
Isso deve funcionar muito rapidamente (alguns testes cronometrados são incluídos abaixo) com entrada de qualquer tamanho. Algumas notas sobre como:
-
%código%
- Como o objetivo da operação a seguir é obter o arquivo inteiro de
export LC_ALL=C
empilhado em linha com o arquivo ./F
lineno, os únicos caracteres com os quais realmente precisamos nos preocupar são ASCII ./L
dígitos e [0-9]
dois pontos.
- Por essa razão, é mais simples se preocupar em encontrar esses 11 caracteres em um conjunto de 128 possíveis do que se o UTF-8 estivesse envolvido.
-
%código%
- Isso insere a string
:
na cabeça de cada linha em stdin - ou grep -n ''
.
-
%código%
-
LINENO:
não classifica seus arquivos de entrada, e em vez disso, (corretamente) presume que eles são pré-definidos e <./F
os ordena em sort -t: -nmk1,1 ./L -
ordem ordenada, ignorando basicamente qualquer coisa além de qualquer possível sort
st ocorrendo -m
caracteres de dois pontos de qualquer maneira.
- Embora isso possa exigir algum espaço temporário para fazer (dependendo de quão distantes algumas seqüências podem ocorrer) , ele não exigirá muito em comparação a uma classificação adequada, e será muito rápido porque envolve zero backtracking.
-
-numerically
produzirá um único fluxo onde qualquer lineno em -k1,1
imediatamente precederá as linhas correspondentes em -t:
. As linhas de sort
sempre vêm em primeiro lugar porque são mais curtas.
-
%código%
- Se a linha atual corresponder a
./L
colon ./F
elete da saída. Senão, imprima automaticamente a linha atual e ./L
ext.
- E assim
sed /:/d\;n
extrai a saída de /:/
para somente pares de linhas seqüenciais que não correspondem à vírgula e à linha seguinte - ou apenas a uma linha de d
e o próximo.
-
%código%
-
n
sed
comprime de saída aquelas de suas linhas de entrada que não contêm pelo menos uma de suas sort
elimitadoras - e assim as linhas ./L
são removidas completamente.
- Para essas linhas, o primeiro
cut -sd: -f2-
delimitado por dois pontos percentuais cut
é -s
ausente - e assim vai todo o lineno de -d:
inserido.
teste de entrada pequena
seq 5 | sed -ne'2,3!w /tmp/L
s/.*/a-z &\& 0-9/p' >/tmp/F
... gera 5 linhas de entrada de amostra. Então ...
( export LC_ALL=C; </tmp/F \
grep -n '' | sort -t: -nmk1,1 ./L - |
sed /:/d\;n | cut -sd: -f2-
)| head - /tmp[FL]
... imprime ...
==> standard input <==
a-z 1& 0-9
a-z 4& 0-9
a-z 5& 0-9
==> /tmp/F <==
a-z 1& 0-9
a-z 2& 0-9
a-z 3& 0-9
a-z 4& 0-9
a-z 5& 0-9
==> /tmp/L <==
1
4
5
testes cronometrados maiores
Eu criei alguns arquivos muito grandes:
seq 5000000 | tee /tmp/F |
sort -R | head -n1500000 |
sort -n >/tmp/L
... o qual coloca 5mil linhas em ./L
e 1,5mil linhas aleatoriamente selecionadas em :
. Eu então fiz:
time \
( export LC_ALL=C
grep -n '' | sort -t: -nmk1,1 ./L - |
sed /:/d\;n | cut -sd: -f2-
) <./F |wc - l
Impresso:
1500000
grep -n '' \
0.82s user 0.05s system 73% cpu 1.185 total
sort -t: -nmk1,1 /tmp/L - \
0.92s user 0.11s system 86% cpu 1.185 total
sed /:/d\;n \
1.02s user 0.14s system 98% cpu 1.185 total
cut -sd: -f2- \
0.79s user 0.17s system 80% cpu 1.184 total
wc -l \
0.05s user 0.07s system 10% cpu 1.183 total
(adicionei as barras invertidas)
Entre as soluções atualmente oferecidas aqui, esta é a mais rápida de todas, exceto uma, quando comparada com o conjunto de dados gerado acima na minha máquina. Dos outros, apenas um chegou perto de disputar o segundo lugar, e esse é o -f
aqui do meuh.
Esta não é de forma alguma a solução original oferecida - ela caiu um terço de seu tempo de execução graças a conselhos / inspiração oferecidos por outras pessoas. Veja o histórico de postagens para soluções mais lentas (mas por quê?) .
Além disso, vale a pena notar que algumas outras respostas podem muito bem ser melhor se não fossem a arquitetura multi-cpu do meu sistema e a execução simultânea de cada um dos processos naquele pipeline. Todos eles trabalham ao mesmo tempo - cada um em seu próprio núcleo de processador - passando os dados e fazendo sua pequena parte do todo. É bem legal.
mas a solução mais rápida é ...
Mas esta não é a solução mais rápida. A solução mais rápida oferecida aqui, com as mãos para baixo, é o programa C . Eu chamei de cut
. Depois de copiá-lo para o meu X clipboard, eu compilei como:
xsel -bo | cc -xc - -o cselect
Eu então fiz:
time \
./cselect /tmp/L /tmp/F |
wc -l
... e os resultados foram ...
1500000
./cselect /tmp/L /tmp/F \
0.50s user 0.05s system 99% cpu 0.551 total
wc -l \
0.05s user 0.05s system 19% cpu 0.551 total