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
./F
apilado en línea con ./L
el 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 -
sort
se niega a ordenar sus archivos de entrada en absoluto, y en su lugar (correctamente) presume que se han clasificado previamente y -m
les Erges en -numerically
forma ordenada, ignorando básicamente cualquier cosa más allá de cualquier posible -k1,1
que 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.
sort
generará una sola secuencia donde cualquier entrada de lineno ./L
precederá inmediatamente a las líneas correspondientes ./F
. ./L
Las líneas siempre vienen primero porque son más cortas.
sed /:/d\;n
- Si la línea actual coincide con
/:/
dos puntos, d
elíjala de la salida. De lo contrario, imprima automáticamente la n
línea actual y la ext.
- Y, por lo tanto,
sed
elimina sort
la 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 ./L
y luego a la siguiente.
cut -sd: -f2-
cut
-s
elimina 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í ./L
las líneas se eliminan por completo.
- Para aquellas líneas que lo hacen, su primer campo
:
delimitado por dos puntos -f
está cut
lejos, y así desaparecen todos grep
los 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/F
y 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