grep -n | sort | sed | cut
( export LC_ALL=C
grep -n '' | sort -t: -nmk1,1 ./L - |
sed /:/d\;n | cut -sd: -f2-
) <./F
Eso debería funcionar bastante rápido (algunas pruebas cronometradas se incluyen a continuación) con entradas de cualquier tamaño. Algunas notas sobre cómo:
export LC_ALL=C
- Debido a que el objetivo de la siguiente operación es obtener todo el archivo
./Fapilado en línea con ./Lel archivo de lineno, los únicos caracteres de los que realmente tendremos que preocuparnos son los [0-9]dígitos ASCII y los :dos puntos.
- Por esa razón, es más simple preocuparse por encontrar esos 11 caracteres en un conjunto de 128 posibles que si UTF-8 está involucrado de otra manera.
grep -n ''
- Esto inserta la cadena
LINENO:en el encabezado de cada línea en stdin - o <./F.
sort -t: -nmk1,1 ./L -
sortse niega a ordenar sus archivos de entrada en absoluto, y en su lugar (correctamente) presume que se han clasificado previamente y -mles Erges en -numericallyforma ordenada, ignorando básicamente cualquier cosa más allá de cualquier posible -k1,1que ocurre st -t:carácter de dos puntos de todos modos.
- Si bien esto puede requerir cierto espacio temporal (dependiendo de qué tan separadas puedan estar algunas secuencias) , no requerirá mucho en comparación con un tipo adecuado, y será muy rápido porque implica un retroceso cero.
sortgenerará una sola secuencia donde cualquier entrada de lineno ./Lprecederá inmediatamente a las líneas correspondientes ./F. ./LLas líneas siempre vienen primero porque son más cortas.
sed /:/d\;n
- Si la línea actual coincide con
/:/dos puntos, delíjala de la salida. De lo contrario, imprima automáticamente la nlínea actual y la ext.
- Y, por lo tanto,
sedelimina sortla salida a solo pares de líneas secuenciales que no coinciden con dos puntos y la siguiente línea, o, solo a una línea desde ./Ly luego a la siguiente.
cut -sd: -f2-
cut -selimina de la salida los de sus líneas de entrada que no contienen al menos una de sus -d:cadenas de eliminación, y así ./Llas líneas se eliminan por completo.
- Para aquellas líneas que lo hacen, su primer campo
:delimitado por dos puntos -festá cutlejos, y así desaparecen todos greplos lineno insertados.
pequeña prueba de entrada
seq 5 | sed -ne'2,3!w /tmp/L
s/.*/a-z &\& 0-9/p' >/tmp/F
... genera 5 líneas de entrada de muestra. Luego...
( export LC_ALL=C; </tmp/F \
grep -n '' | sort -t: -nmk1,1 ./L - |
sed /:/d\;n | cut -sd: -f2-
)| head - /tmp[FL]
...huellas dactilares...
==> 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
pruebas cronometradas más grandes
Creé un par de archivos bastante grandes:
seq 5000000 | tee /tmp/F |
sort -R | head -n1500000 |
sort -n >/tmp/L
... que ponen 5mil líneas /tmp/Fy 1.5mil líneas seleccionadas al azar de eso /tmp/L. Entonces hice:
time \
( export LC_ALL=C
grep -n '' | sort -t: -nmk1,1 ./L - |
sed /:/d\;n | cut -sd: -f2-
) <./F |wc - l
Impreso:
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
(Agregué las barras invertidas allí)
Entre las soluciones que se ofrecen actualmente aquí, esta es la más rápida de todas, pero una cuando se enfrenta al conjunto de datos generado anteriormente en mi máquina. De los otros, solo uno estuvo cerca de competir por el segundo lugar, y ese es meuh perl aquí .
Esta no es de ninguna manera la solución original ofrecida: ha reducido un tercio de su tiempo de ejecución gracias a los consejos / inspiración ofrecidos por otros. Vea el historial de publicaciones para soluciones más lentas (pero ¿por qué?) .
Además, vale la pena señalar que algunas otras respuestas podrían contestar mejor si no fuera por la arquitectura de múltiples CPU de mi sistema y la ejecución concurrente de cada uno de los procesos en esa tubería. Todos trabajan al mismo tiempo, cada uno en su propio núcleo de procesador, pasando los datos y haciendo su pequeña parte del conjunto. Es genial.
pero la solución más rápida es ...
Pero no es la solución más rápida. La solución más rápida que aquí se ofrecen, las manos hacia abajo, es el programa C . Yo lo llamaba cselect. Después de copiarlo en mi portapapeles X, lo compilé como:
xsel -bo | cc -xc - -o cselect
Entonces hice:
time \
./cselect /tmp/L /tmp/F |
wc -l
... y los resultados fueron ...
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