Tengo poco más de 100 archivos de texto en un directorio, que funcionan como una base de datos simple con cada línea que contiene un registro. En total, estos archivos suman alrededor de 25 GB. Sin embargo, los registros no están ordenados alfabéticamente y hay muchos duplicados, por lo que para alfabetizar el contenido de todos los ~ 100 archivos de texto usando algo como sort -u, primero estoy tratando de combinar todos estos archivos en un solo archivo de texto grande Un cat simple no sería adecuado porque el comienzo y el final de los 100 archivos de texto no contienen nuevas líneas, lo que (a mi entender) haría que el último registro de un archivo se fusionara con el primer registro del siguiente archivo.

¿Qué soluciones hay que me permitan concatenar mis archivos de texto y asegurarme de que haya un solo carácter de línea nueva que los separe?

0
Hashim 9 sep. 2018 a las 18:24

4 respuestas

La mejor respuesta

Un simple

sort -u *.db > uniquified # adjust glob as needed

Deberías hacerlo; sort interpondrá nuevas líneas entre archivos si fuera necesario.

cat *.db | sort -u

Es un clásico UUoC y la falla con los archivos que carecen de nuevas líneas finales no es El único problema.

Dicho esto, 25GB probablemente no caben en tu RAM, por lo que sort terminará creando archivos temporales de todos modos. Puede resultar más rápido ordenar los archivos en cuatro o cinco grupos y luego combinar los resultados. Eso podría aprovechar mejor la gran cantidad de duplicados. Pero solo experimentaría si el comando simple realmente toma una cantidad exorbitante de tiempo.

Aun así, ordenar los archivos individualmente es probablemente aún más lento; por lo general, la mejor opción es maximizar los recursos de memoria para cada invocación de sort. Podría, por ejemplo, usar xargs con la opción -n para dividir la lista de archivos en grupos de un par de docenas de archivos cada uno. Una vez que haya ordenado cada grupo, puede usar sort -m para fusionar los temporales ordenados.

Un par de notas sobre cómo mejorar la velocidad de clasificación:

  1. Use LC_COLLATE=C sort si no necesita una clasificación de datos alfabéticos con reconocimiento local. Eso generalmente acelera la clasificación por un factor de tres o cuatro.

  2. Evite usar discos RAM para espacio temporal. (En muchas distribuciones de Linux, /tmp es un disco RAM.) Dado que sort usa discos temporales cuando se queda sin RAM, colocar el temporal en un disco RAM es contraproducente. Por la misma razón, no coloque sus propios archivos de salida temporales en /tmp. /var/tmp debe ser un disco real; incluso mejor, si es posible, use una segunda unidad de disco (no una unidad USB lenta, por supuesto).

  3. Evite golpear su máquina hacia abajo con un intercambio excesivo mientras realiza la clasificación, apagando el intercambio:

    sudo swapoff -a
    

    Puede volver a encenderlo después, aunque personalmente ejecuto mi máquina de esta manera todo el tiempo porque evita caer en una completa falta de respuesta bajo la presión de la memoria.

  4. Lo ideal es ajustar -S para que sort use la mayor cantidad de memoria posible y evite el uso de temporarios internos clasificando los fragmentos que se ajusten a esa cantidad de memoria. (La fusión de los fragmentos ordenados es mucho más rápida que la clasificación, y lee y escribe secuencialmente sin necesidad de espacio adicional en el disco). Probablemente necesite experimentar un poco para encontrar un buen tamaño de fragmento.

4
rici 10 sep. 2018 a las 18:18

Puedes usar awk.

$ od -t x1 file1
0000000 72 65 63 6f 72 64 31 0a 72 65 63 6f 72 64 32
0000017
$ od -t x1 file2
0000000 72 65 63 6f 72 64 31 0a 72 65 63 6f 72 64 32 0a
0000020 72 65 63 6f 72 64 33
0000027
$ awk 1 file1 file2
record1
record2
record1
record2
record3

1 es un script awk aquí, lo que significa imprimir todos los registros

2
oguz ismail 9 sep. 2018 a las 16:41

sort * debería ser todo lo que necesita, pero en caso de que necesite agregar nuevas líneas al contenido del archivo para que una herramienta posterior lo procese, aquí le mostramos cómo hacerlo:

$ ls
file1  file2
$ cat file1
foo$
$ cat file2
bar$
$ cat file1 file2
foobar$

$ find . -type f -exec sh -c '(cat {}; printf "\\n")' \;
foo
bar

¡Eso es, por supuesto, asumir que su cat puede manejar archivos que no terminan en nuevas líneas!

1
Ed Morton 10 sep. 2018 a las 12:58

Le diría que cree ese archivo concatenando todos los archivos de entrada e intercalando una nueva línea en el medio:

out=newfile.txt
rm -f "$out"
for f in *.txt
do
    cat "$f" >> "$out"
    echo >> "$out"
done

Ahora puedes ordenarlo. O elimine las líneas vacías, en caso de que piense que podría haber algún archivo de entrada con una nueva línea al final.

2
Poshi 9 sep. 2018 a las 15:46