Estoy seguro de que alguien ha tenido la siguiente necesidad, ¿cuál es una forma rápida de dividir un gran archivo .gz por línea? El archivo de texto subyacente tiene 120 millones de filas. No tengo suficiente espacio en el disco para comprimir todo el archivo a la vez, así que me preguntaba si alguien conoce un script o herramienta bash / perl que pueda dividir el archivo (ya sea .gz o .txt interno) en archivos de 3x 40 millones de líneas . es decir, llamarlo así:
bash splitter.sh hugefile.txt.gz 4000000 1
would get lines 1 to 40 mn
bash splitter.sh hugefile.txt.gz 4000000 2
would get lines 40mn to 80 mn
bash splitter.sh hugefile.txt.gz 4000000 3
would get lines 80mn to 120 mn
Tal vez hacer una serie de estos sea una solución o el gunzip -c requeriría suficiente espacio para descomprimir todo el archivo (es decir, el problema original): gunzip -c hugefile.txt.gz | cabeza 4000000
Nota: No puedo obtener un disco extra.
¡Gracias!
Respuestas:
Cómo hacer esto mejor depende de lo que quieras:
Si desea una sola parte del archivo , su idea es usar
gunzip
yhead
es correcta. Puedes usar:Eso generaría las primeras 4000000 líneas en la salida estándar: probablemente desee agregar otra tubería para hacer algo con los datos.
Para obtener las otras partes, usaría una combinación de
head
ytail
, como:para obtener el segundo bloque.
No,
gunzip -c
no requiere espacio en disco: hace todo en la memoria y luego lo transfiere a stdout.Si desea crear todas las partes de una vez , es más eficiente crearlas todas con un solo comando, porque el archivo de entrada solo se lee una vez. Una buena solución es usar
split
; ver la respuesta de jim mcnamara para más detalles.fuente
gzip
no conoce el límite (que proviene de un proceso diferente). Sihead
se usa,head
saldrá cuando haya recibido suficiente, y esto se propagará agzip
(a través de SIGPIPE, consulte Wikipedia). Paratail
esto no es posible, entonces sí,gzip
descomprimirá todo.tubería para dividir use gunzip -c o zcat para abrir el archivo
Agregue especificaciones de salida al comando de división.
fuente
Como está trabajando en una secuencia (no rebobinable), querrá usar la forma de cola '+ N' para obtener líneas que comiencen desde la línea N en adelante.
fuente
Consideraría usar split .
fuente
Divide directamente el archivo .gz en archivos .gz:
Creo que esto es lo que OP quería, porque no tiene mucho espacio.
fuente
Aquí hay un script de Python para abrir un conjunto global de archivos de un directorio, comprimirlos si es necesario y leerlos línea por línea. Solo usa el espacio necesario en la memoria para guardar los nombres de archivo y la línea actual, más un poco de sobrecarga.
El comando de línea de impresión enviará cada línea a la salida estándar, para que pueda redirigir a un archivo. Alternativamente, si nos hace saber lo que quiere hacer con las líneas, puedo agregarlo al script de Python y no necesitará dejar trozos del archivo.
fuente
Aquí hay un programa perl que se puede usar para leer stdin y dividir las líneas, canalizando cada grupo a un comando separado que puede usar una variable de shell $ SPLIT para enrutarlo a un destino diferente. Para su caso, se invocaría con
zcat hugefile.txt.gz | perl xsplit.pl 40000000 'cat > tmp$SPLIT.txt; do_something tmp$SPLIT.txt; rm tmp$SPLIT.txt'
Lo sentimos, el procesamiento de la línea de comandos es un poco torpe, pero se entiende la idea.
fuente