2011-06-13 19 views
5

Tengo algunos archivos clasificados y descomprimidos en un directorio. ¿Cómo combino algunos de ellos en otro archivo ordenado y comprimido? En este momento estoy usando fifos explícitos. ¿Hay alguna manera de hacerlo en Bash sin? Soy un poco novato bash, así que disculpen mi falta de estilo.Combinación de archivos ordenados con fifos

#!/bin/bash 
# Invocation ./merge [files ... ] 
# Turns an arbitrary set of sorted, gzipped files into a single sorted, gzipped file, 
# printed to stdout. Redirect this script's output! 
for f in [email protected] 
do 
    mkfifo $f.raw 
    gzcat $f > $f.raw & 
    # sort -C $f.raw 
done 
sort -mu *.raw | gzip -C# prints to stdout. 
rm -f *.raw 

Busco a convertir esto en algo así como ...

sort -mu <(gzcat $1) <(gzcat $2) <(gzcat $3) ... | gzip -9C# prints to stdout. 

... pero no saben cómo. ¿Necesito un bucle para construir los parámetros en la cadena? ¿Hay algún tipo de atajo mágico para esto? ¿Tal vez map gzcat [email protected]?

NOTA: Cada uno de los archivos supera los 10 GB (y 100 GB descomprimidos). Tengo una unidad de 2TB, así que esto no es realmente un problema. Además, este programa DEBE ejecutarse en O (n) o se vuelve inviable.

+1

veo que ha editado la pregunta mientras yo estaba respondiendo - sí, necesita un bucle para construir la cadena de comandos, y, o bien '' eval' o fiesta -c "$ cmd" 'para ejecutarlo al final . –

Respuesta

3

Puede combinar eval y 'proceso de sustitución' con Bash. Suponiendo que los nombres de los archivos básicos no contienen espacios (que, teniendo en cuenta que se utiliza en lugar de [email protected]"[email protected]" es probablemente el caso), entonces algo como:

cmd="sort -mu" 
for file in "[email protected]" 
do cmd="$cmd <(gzip -cd $file)" 
done 
eval $cmd | gzip -c9 > outputfile.gz 

También se puede utilizar en lugar de bash -c "$cmd"eval $cmd en la última línea . Si hay espacios en los nombres de los archivos, debe trabajar un poco más. Esto funciona si los nombres no contienen comillas simples:

cmd="sort -mu" 
for file in "[email protected]" 
do cmd="$cmd <(gzip -cd '$file')" 
done 
eval $cmd | gzip -c9 > outputfile.gz 

con comillas simples en los nombres de archivo también, usted tiene que trabajar mucho más duro.

1

Para mí, su pregunta es un poco confuso, pero si entiendo su necesidad, intente esto:

gunzip -c file1 file2 .... | sort | gzip -9 > mergedFile.gz 

Si usted quiere hacer todos los archivos de un tipo determinado en 1 dir, a continuación, puede utilizar file*.type como la lista de entrada a gunzip; de lo contrario, según mi ejemplo, tendrá que listar cada archivo explícitamente.

La opción -c indica 'enviar la salida a la salida estándar', que es el leído por el tubo, enviado a sort, que envía su salida a la salida estándar, la tubería, y en gzip, con ella la salida estándar está siendo redirigido hacia el final del archivo . El es la compresión más alta, que le proporciona el archivo más pequeño (para gzip), pero lleva más tiempo. Puede dar un número explícito entre -1 y -9 para ajustar el tamaño/tiempo de compresión para comprimir la compensación según sus necesidades.

Espero que esto ayude.

+0

Realmente quiero usar sort -mu, que no funcionará si hacemos gunzip de una vez. Pasa de O (nlogn) a O (n). –

+0

Normalmente usaría un 'gzip -c-9' explícito, pero supongo que eso funcionará. –

+0

¿Entonces tiene archivos grandes y está buscando una forma de paralelizar el proceso clasificando previamente archivos más pequeños y luego fusionándolos al final? ¿Y tiene varias CPU que puede asignar a cada proceso de clasificación más pequeño? ¿Estás buscando ahorrar tiempo, o CPU, o ??? Hay un número significativo de personas interesadas en la optimización del rendimiento aquí en S.O. Puede agregar etiquetas para la evaluación comparativa, las pruebas y el ajuste del rendimiento para obtener mejores consejos sobre cómo abordar esto. Buena suerte. – shellter

1

Con comillas simples en los nombres de los archivos también, tiene que trabajar mucho más.

Aquí hay una manera de evitar comillas simples dentro de los nombres de archivo (o rutas de archivos) que obtendrán eval 'ed en variables rodeadas por comillas simples.

(
esc="'\''" 
file="/Applications/iWork '09/Pages.app" 
file="${file//\'/${esc}}" 
#echo "'${file}'"; ls -bdl "'${file}'" 
evalstr="echo '${file}'; ls -bdl '${file}'" 
#set -xv 
eval "${evalstr}" 
) 
Cuestiones relacionadas