Come dividere un file di testo di grandi dimensioni in file più piccoli con uguale numero di righe?


517

Ho un grande file di testo semplice (per numero di righe) che vorrei dividere in file più piccoli, anche per numero di righe. Quindi, se il mio file ha circa 2 milioni di righe, vorrei dividerlo in 10 file che contengono 200.000 righe o 100 file che contengono 20.000 righe (più un file con il resto; essere uniformemente divisibili non ha importanza).

Potrei farlo abbastanza facilmente in Python ma mi chiedo se esiste un modo ninja di farlo usando utils bash e unix (al contrario del loop manuale e del conteggio / partizionamento delle linee).


2
Per curiosità, dopo che sono "divisi", come si possono "combinare"? Qualcosa come "cat part2 >> part1"? O c'è un'altra utility ninja? stai aggiornando la tua domanda?
Dlamotte,

7
Per rimetterlo insieme,cat part* > original
Mark Byers,

9
sì, il gatto è l'abbreviazione di concatenato. In generale apropos è utile per trovare i comandi appropriati. IE vede l'output di:
apropos

@pixelbeat È fantastico, grazie
danben

3
A parte questo, gli utenti di OS X dovrebbero assicurarsi che il loro file contenga interruzioni di linea / indicatori di fine linea (LF) in stile LINUX o UNIX anziché MAC OS X - indicatori di fine linea in stile (CR) - la divisione e I comandi csplit non funzioneranno se le tue interruzioni simili sono Resi carrello invece di LineFeeds. TextWrangler del software BareBones può aiutarti in questo se sei su Mac OS. Puoi scegliere l'aspetto dei tuoi caratteri di interruzione di riga. quando salvi (o Salva con nome ...) i tuoi file di testo.

Risposte:


858

Hai guardato il comando split?

$ 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

Potresti fare qualcosa del genere:

split -l 200000 filename

che creerà file ciascuno con 200000 righe denominate xaa xab xac...

Un'altra opzione, suddivisa per dimensione del file di output (si divide ancora in caso di interruzioni di riga):

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

crea file come output_prefix01 output_prefix02 output_prefix03 ...ciascuno della dimensione massima di 20 megabyte.


16
puoi anche dividere un file per dimensione: split -b 200m filename(m per megabyte, k per kilobyte o nessun suffisso per byte)
Abhi Beckert

137
diviso per dimensione e assicurati che i file siano divisi in corrispondenza delle interruzioni di riga: dividi -C 200m nomefile
Clayton Stanley

2
split produce output confusi con input Unicode (UTF-16). Almeno su Windows con la versione che ho.
Vertigo,

4
@geotheory, assicurati di seguire i consigli di LeberMac precedentemente nel thread sulla prima conversione di terminazioni di linea CR (Mac) in terminazioni di linea LR (Linux) utilizzando TextWrangler o BBEdit. Ho avuto lo stesso identico problema fino a quando non ho trovato quel consiglio.
sstringer,

6
-dl'opzione non è disponibile su OSX, utilizzare gsplitinvece. Spero che questo sia utile per l'utente Mac.
user5698801


39

Sì, c'è un splitcomando. Suddividerà un file per linee o byte.

$ 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.

Ho provato georgec @ ATGIS25 ~ $ split -l 100000 /cygdrive/P/2012/Job_044_DM_Radio_Propogation/Working/FinalPropogation/TRC_Longlands/trc_longlands.txt ma non ci sono file divisi nella directory - dov'è l'output?
GeorgeC

1
Dovrebbe essere nella stessa directory. Ad esempio, se voglio scissione da 1.000.000 righe per file, procedere come segue: split -l 1000000 train_file train_file.e nella stessa directory vado a prendere train_file.aacon il primo milione, poi trail_file.abcon il prossimo milione, ecc
Will

1
@GeorgeC e si può ottenere le directory di output personalizzati con il prefisso: split input my/dir/.
Ciro Santilli 24 冠状 病 六四 事件 法轮功

15

uso split

Dividi un file in pezzi di dimensioni fisse, crea file di output contenenti sezioni consecutive di INPUT (input standard se non ne viene fornito nessuno o INPUT è `- ')

Syntax split [options] [INPUT [PREFIX]]

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


13

Uso:

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

Qui, 1 e 100 sono i numeri di riga in cui acquisirai output.txt.


In questo modo si ottengono solo le prime 100 righe, è necessario eseguirne il loop per dividere successivamente il file nel successivo 101..200 ecc. O semplicemente utilizzare splitcome già indicato da tutte le risposte principali qui.
Tripleee

10

dividere il file "file.txt" in file di 10000 righe:

split -l 10000 file.txt

9

split(da GNU coreutils, dalla versione 8.8 dal 22-12-2010 ) include il seguente parametro:

-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

Pertanto, split -n 4 input output.genererà quattro file ( output.a{a,b,c,d}) con la stessa quantità di byte, ma le linee potrebbero essere interrotte nel mezzo.

Se vogliamo preservare le linee complete (cioè divise per linee), allora dovrebbe funzionare:

split -n l/4 input output.

Risposta correlata: https://stackoverflow.com/a/19031247


9

Nel caso in cui desideri solo dividere per x numero di righe ogni file, le risposte fornite splitsono OK. Ma sono curioso che nessuno abbia prestato attenzione ai requisiti:

  • "senza doverli contare" -> usando wc + cut
  • "Avere il resto nel file extra" -> split fa per impostazione predefinita

Non posso farlo senza "wc + cut", ma lo sto usando:

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

Questo può essere facilmente aggiunto alle funzioni di bashrc in modo da poterlo invocare semplicemente passando nome file e blocchi:

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

Nel caso in cui desideri solo x blocchi senza resto nel file aggiuntivo, basta adattare la formula per sommarlo (blocchi - 1) su ciascun file. Uso questo approccio perché di solito voglio solo x numero di file anziché x linee per file:

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

Puoi aggiungerlo a uno script e chiamarlo la tua "via ninja", perché se nulla soddisfa le tue esigenze, puoi costruirlo :-)


Oppure, basta usare l' -nopzione di split.
Amit Naidu,

8

puoi anche usare awk

awk -vc=1 'NR%200000==0{++c}{print $0 > c".txt"}' largefile

3
awk -v lines=200000 -v fmt="%d.txt" '{print>sprintf(fmt,1+int((NR-1)/lines))}'
Mark Edgar

0

HDFS ottiene file di piccole dimensioni e si riversa nelle dimensioni delle proprietà.

Questo metodo causerà l'interruzione di riga

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

Cerco di ottenere e dividere in circa 128 MB ogni file.

# 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}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.