¿Cómo dividir un archivo de texto grande en archivos más pequeños con igual número de líneas?

517

Tengo un archivo de texto plano grande (por número de líneas) que me gustaría dividir en archivos más pequeños, también por número de líneas. Entonces, si mi archivo tiene alrededor de 2M líneas, me gustaría dividirlo en 10 archivos que contengan 200k líneas, o 100 archivos que contengan 20k líneas (más un archivo con el resto; ser igualmente divisible no importa).

Podría hacer esto con bastante facilidad en Python, pero me pregunto si hay algún tipo de forma ninja de hacer esto usando bash y unix utils (en lugar de bucle manual y recuento / partición de líneas).

danben
fuente
2
Por curiosidad, después de que están "divididos", ¿cómo se "combinan"? ¿Algo así como "gato parte2 >> parte1"? ¿O hay otra utilidad ninja? ¿Te importaría actualizar tu pregunta?
Dlamotte
77
Para volver a armarlo,cat part* > original
Mark Byers
99
sí, gato es la abreviatura de concatenar. En general, a propósito es útil para encontrar los comandos apropiados. IE ver el resultado de: apropos split
pixelbeat
@pixelbeat Eso es bastante genial, gracias
danben
3
Por otro lado, los usuarios de OS X deben asegurarse de que su archivo contenga saltos de línea / indicadores de fin de línea (LF) de estilo LINUX o UNIX en lugar de MAC OS X - indicadores de fin de línea (CR) de estilo - la división y Los comandos csplit no funcionarán si sus saltos similares son Devoluciones de carro en lugar de LineFeeds. TextWrangler del software BareBones puede ayudarlo con esto si tiene Mac OS. Puedes elegir cómo quieres que se vean tus caracteres de salto de línea. cuando guarda (o Guardar como ...) sus archivos de texto.

Respuestas:

858

¿Has mirado el comando dividir?

$ split --help
Usage: split [OPTION] [INPUT [PREFIX]]
Output fixed-size pieces of INPUT to PREFIXaa, PREFIXab, ...; default
size is 1000 lines, and default PREFIX is `x'.  With no INPUT, or when INPUT
is -, read standard input.

Mandatory arguments to long options are mandatory for short options too.
  -a, --suffix-length=N   use suffixes of length N (default 2)
  -b, --bytes=SIZE        put SIZE bytes per output file
  -C, --line-bytes=SIZE   put at most SIZE bytes of lines per output file
  -d, --numeric-suffixes  use numeric suffixes instead of alphabetic
  -l, --lines=NUMBER      put NUMBER lines per output file
      --verbose           print a diagnostic to standard error just
                            before each output file is opened
      --help     display this help and exit
      --version  output version information and exit

Podrías hacer algo como esto:

split -l 200000 filename

que creará archivos cada uno con 200000 líneas llamadas xaa xab xac...

Otra opción, dividida por el tamaño del archivo de salida (todavía se divide en saltos de línea):

 split -C 20m --numeric-suffixes input_filename output_prefix

crea archivos como output_prefix01 output_prefix02 output_prefix03 ...cada uno de tamaño máximo de 20 megabytes.

Mark Byers
fuente
16
también puede dividir un archivo por tamaño: split -b 200m filename(m para megabytes, k para kilobytes o sin sufijo para bytes)
Abhi Beckert
137
dividir por tamaño y garantizar que los archivos se dividan en saltos de línea: dividir -C 200m nombre de archivo
Clayton Stanley
2
split produce una salida confusa con entrada Unicode (UTF-16). Al menos en Windows con la versión que tengo.
Vértigo
44
@geotheory, asegúrese de seguir los consejos de LeberMac anteriormente en el hilo sobre la primera conversión de terminaciones de línea CR (Mac) a terminaciones de línea LR (Linux) usando TextWrangler o BBEdit. Tuve exactamente el mismo problema que tú hasta que encontré ese consejo.
sstringer
66
-dopción no está disponible en OSX, use gspliten su lugar. Espero que esto sea útil para los usuarios de Mac.
user5698801
80

¿Qué tal el comando dividir ?

split -l 200000 mybigfile.txt
Robert Christie
fuente
39

Sí, hay un splitcomando. Dividirá un archivo por líneas o bytes.

$ split --help
Usage: split [OPTION]... [INPUT [PREFIX]]
Output fixed-size pieces of INPUT to PREFIXaa, PREFIXab, ...; default
size is 1000 lines, and default PREFIX is `x'.  With no INPUT, or when INPUT
is -, read standard input.

Mandatory arguments to long options are mandatory for short options too.
  -a, --suffix-length=N   use suffixes of length N (default 2)
  -b, --bytes=SIZE        put SIZE bytes per output file
  -C, --line-bytes=SIZE   put at most SIZE bytes of lines per output file
  -d, --numeric-suffixes  use numeric suffixes instead of alphabetic
  -l, --lines=NUMBER      put NUMBER lines per output file
      --verbose           print a diagnostic just before each
                            output file is opened
      --help     display this help and exit
      --version  output version information and exit

SIZE may have a multiplier suffix:
b 512, kB 1000, K 1024, MB 1000*1000, M 1024*1024,
GB 1000*1000*1000, G 1024*1024*1024, and so on for T, P, E, Z, Y.
Dave Kirby
fuente
Intenté georgec @ ATGIS25 ~ $ split -l 100000 /cygdrive/P/2012/Job_044_DM_Radio_Propogation/Working/FinalPropogation/TRC_Longlands/trc_longlands.txt pero no hay archivos divididos en el directorio, ¿dónde está la salida?
GeorgeC
1
Debería estar en el mismo directorio. Por ejemplo, si quiero dividir entre 1,000,000 de líneas por archivo, haga lo siguiente: split -l 1000000 train_file train_file.y en el mismo directorio obtendré train_file.aael primer millón, luego trail_file.abel próximo millón, etc.
Será
1
@GeorgeC y se puede obtener directorios de salida personalizado con el prefijo: split input my/dir/.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
15

utilizar split

Dividir un archivo en piezas de tamaño fijo, crea archivos de salida que contienen secciones consecutivas de ENTRADA (entrada estándar si no se proporciona ninguna o la ENTRADA es `- ')

Syntax split [options] [INPUT [PREFIX]]

http://ss64.com/bash/split.html

zmbush
fuente
13

Utilizar:

sed -n '1,100p' filename > output.txt

Aquí, 1 y 100 son los números de línea que capturará output.txt.

Harshwardhan
fuente
Esto solo obtiene las primeras 100 líneas, debe hacer un bucle para dividir sucesivamente el archivo en los siguientes 101..200 etc. O simplemente use splitcomo todas las respuestas principales aquí ya le dicen.
tripleee
10

dividir el archivo "file.txt" en archivos de 10000 líneas:

split -l 10000 file.txt
ialqwaiz
fuente
9

split(de GNU coreutils, desde la versión 8.8 del 2010-12-22 ) incluye el siguiente parámetro:

-n, --number=CHUNKS     generate CHUNKS output files; see explanation below

CHUNKS may be:
  N       split into N files based on size of input
  K/N     output Kth of N to stdout
  l/N     split into N files without splitting lines/records
  l/K/N   output Kth of N to stdout without splitting lines/records
  r/N     like 'l' but use round robin distribution
  r/K/N   likewise but only output Kth of N to stdout

Por lo tanto, split -n 4 input output.generará cuatro archivos ( output.a{a,b,c,d}) con la misma cantidad de bytes, pero las líneas pueden estar divididas en el medio.

Si queremos preservar las líneas completas (es decir, divididas por líneas), esto debería funcionar:

split -n l/4 input output.

Respuesta relacionada: https://stackoverflow.com/a/19031247

Denilson Sá Maia
fuente
9

En caso de que solo desee dividir por x número de líneas cada archivo, las respuestas dadas sobre splitestán bien. Pero, tengo curiosidad por saber que nadie prestó atención a los requisitos:

  • "sin tener que contarlos" -> usando wc + cut
  • "tener el resto en un archivo extra" -> dividir lo hace por defecto

No puedo hacer eso sin "wc + cut", pero estoy usando eso:

split -l  $(expr `wc $filename | cut -d ' ' -f3` / $chunks) $filename

Esto se puede agregar fácilmente a sus funciones bashrc para que pueda invocarlo pasando nombres de archivo y fragmentos:

 split -l  $(expr `wc $1 | cut -d ' ' -f3` / $2) $1

En caso de que desee solo x fragmentos sin resto en un archivo adicional, simplemente adapte la fórmula para sumarlo (fragmentos - 1) en cada archivo. Utilizo este enfoque porque generalmente solo quiero x número de archivos en lugar de x líneas por archivo:

split -l  $(expr `wc $1 | cut -d ' ' -f3` / $2 + `expr $2 - 1`) $1

Puede agregar eso a un script y llamarlo su "estilo ninja", porque si nada satisface sus necesidades, puede construirlo :-)

m3nda
fuente
O simplemente use la -nopción de split.
Amit Naidu
8

también puedes usar awk

awk -vc=1 'NR%200000==0{++c}{print $0 > c".txt"}' largefile
ghostdog74
fuente
3
awk -v lines=200000 -v fmt="%d.txt" '{print>sprintf(fmt,1+int((NR-1)/lines))}'
Mark Edgar el
0

HDFS getmerge archivo pequeño y derramado en el tamaño de la propiedad.

Este método provocará un salto de línea.

split -b 125m compact.file -d -a 3 compact_prefix

Intento fusionarme y dividirme en aproximadamente 128 MB por archivo.

# split into 128m ,judge sizeunit is M or G ,please test before use.

begainsize=`hdfs dfs -du -s -h /externaldata/$table_name/$date/ | awk '{ print $1}' `
sizeunit=`hdfs dfs -du -s -h /externaldata/$table_name/$date/ | awk '{ print $2}' `
if [ $sizeunit = "G" ];then
    res=$(printf "%.f" `echo "scale=5;$begainsize*8 "|bc`)
else
    res=$(printf "%.f" `echo "scale=5;$begainsize/128 "|bc`)  # celling ref http://blog.csdn.net/naiveloafer/article/details/8783518
fi
echo $res
# split into $res files with number suffix.  ref  http://blog.csdn.net/microzone/article/details/52839598
compact_file_name=$compact_file"_"
echo "compact_file_name :"$compact_file_name
split -n l/$res $basedir/$compact_file -d -a 3 $basedir/${compact_file_name}
Matiji66
fuente