Comment diviser un fichier texte volumineux en fichiers plus petits avec un nombre égal de lignes?

517

J'ai un grand fichier texte (en nombre de lignes) que je voudrais diviser en fichiers plus petits, également en nombre de lignes. Donc, si mon fichier contient environ 2 millions de lignes, je voudrais le diviser en 10 fichiers qui contiennent 200 000 lignes ou 100 fichiers qui contiennent 20 000 lignes (plus un fichier avec le reste; être également divisible n'a pas d'importance).

Je pourrais le faire assez facilement en Python, mais je me demande s'il existe un moyen ninja de le faire en utilisant des utilitaires bash et unix (par opposition aux boucles et aux lignes de comptage / partitionnement manuelles).

danben
la source
2
Par curiosité, après les avoir "divisés", comment les "combiner"? Quelque chose comme "chat part2 >> part1"? Ou existe-t-il un autre utilitaire ninja? vous voulez mettre à jour votre question?
dlamotte
7
Pour le remonter,cat part* > original
Mark Byers
9
oui chat est l'abréviation de concaténé. En général, apropos est utile pour trouver les commandes appropriées. IE voir la sortie de: apropos split
pixelbeat
@pixelbeat C'est plutôt cool, merci
danben
3
Soit dit en passant, les utilisateurs d'OS X doivent s'assurer que leur fichier contient des sauts de ligne / indicateurs de fin de ligne de style LINUX ou UNIX (LF) au lieu de MAC OS X - indicateurs de fin de ligne de style (CR) - le fractionnement et Les commandes csplit ne fonctionneront pas si vos sauts similaires sont des retours chariot au lieu de sauts de ligne. TextWrangler du logiciel BareBones peut vous aider avec cela si vous êtes sur Mac OS. Vous pouvez choisir l'apparence de vos caractères de saut de ligne. lorsque vous enregistrez (ou Enregistrer sous ...) vos fichiers texte.

Réponses:

858

Avez-vous regardé la commande 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

Vous pourriez faire quelque chose comme ça:

split -l 200000 filename

qui va créer des fichiers contenant chacun 200000 lignes nommées xaa xab xac...

Une autre option, divisée par la taille du fichier de sortie (toujours divisée lors des sauts de ligne):

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

crée des fichiers comme output_prefix01 output_prefix02 output_prefix03 ...chacun d'une taille maximale de 20 mégaoctets.

Mark Byers
la source
16
vous pouvez également diviser un fichier par taille: split -b 200m filename(m pour les mégaoctets, k pour les kilo-octets ou aucun suffixe pour les octets)
Abhi Beckert
137
divisez par taille et assurez-vous que les fichiers sont divisés sur les sauts de ligne: split -C 200m nom de fichier
Clayton Stanley
2
split produit une sortie tronquée avec une entrée Unicode (UTF-16). Au moins sur Windows avec la version que j'ai.
Vertigo
4
@geotheory, assurez-vous de suivre les conseils de LeberMac plus tôt dans le fil sur la première conversion des fins de ligne CR (Mac) en fins de ligne LR (Linux) en utilisant TextWrangler ou BBEdit. J'ai eu exactement le même problème que vous jusqu'à ce que je trouve ce conseil.
sstringer du
6
-dn'est pas disponible sur OSX, utilisez gsplitplutôt. J'espère que cela sera utile pour les utilisateurs de Mac.
user5698801
80

Et la commande split ?

split -l 200000 mybigfile.txt
Robert Christie
la source
39

Oui, il y a une splitcommande. Il divisera un fichier par lignes ou octets.

$ 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
la source
Georgec essayé @ ATGIS25 ~ $ split -l 100000 /cygdrive/P/2012/Job_044_DM_Radio_Propogation/Working/FinalPropogation/TRC_Longlands/trc_longlands.txt mais il n'y a pas de fichiers fractionnés dans le répertoire - où est la sortie?
GeorgeC
1
Il doit se trouver dans le même répertoire. Par exemple, si je veux diviser par 1 000 000 lignes par fichier, procédez comme suit: split -l 1000000 train_file train_file.et dans le même répertoire, j'obtiendrai train_file.aaavec le premier million, puis trail_file.abavec le prochain million, etc.
Will
1
@GeorgeC et vous pouvez obtenir des répertoires de sortie personnalisé avec le préfixe: split input my/dir/.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
15

utilisation split

Fractionner un fichier en morceaux de taille fixe, crée des fichiers de sortie contenant des sections consécutives de INPUT (entrée standard si aucune n'est donnée ou INPUT est `- ')

Syntax split [options] [INPUT [PREFIX]]

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

zmbush
la source
13

Utilisation:

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

Ici, 1 et 100 sont les numéros de ligne dans lesquels vous allez capturer output.txt.

Harshwardhan
la source
On obtient ainsi que les 100 premières lignes, vous devez en boucle pour diviser successivement le fichier dans le prochain 101..200 etc. Ou tout simplement utiliser splitcomme toutes les meilleures réponses ici déjà vous dire.
tripleee
10

divisez le fichier "file.txt" en fichiers de 10000 lignes:

split -l 10000 file.txt
ialqwaiz
la source
9

split(de GNU coreutils, depuis la version 8.8 du 22/12/2010 ) inclut le paramètre suivant:

-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

Ainsi, split -n 4 input output.générera quatre fichiers ( output.a{a,b,c,d}) avec la même quantité d'octets, mais les lignes peuvent être interrompues au milieu.

Si nous voulons conserver des lignes complètes (c'est-à-dire divisées par lignes), cela devrait fonctionner:

split -n l/4 input output.

Réponse connexe: https://stackoverflow.com/a/19031247

Denilson Sá Maia
la source
9

Dans le cas où vous souhaitez simplement diviser par x nombre de lignes chaque fichier, les réponses données splitsont correctes. Mais je suis curieux de savoir que personne n'a prêté attention aux exigences:

  • "sans avoir à les compter" -> en utilisant wc + cut
  • "avoir le reste dans un fichier supplémentaire" -> split fait par défaut

Je ne peux pas faire ça sans "wc + cut", mais j'utilise ça:

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

Cela peut être facilement ajouté à vos fonctions bashrc afin que vous puissiez simplement l'invoquer en passant le nom de fichier et les morceaux:

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

Dans le cas où vous ne voulez que x morceaux sans reste dans un fichier supplémentaire, adaptez simplement la formule pour la additionner (morceaux - 1) sur chaque fichier. J'utilise cette approche car généralement je veux juste x nombre de fichiers plutôt que x lignes par fichier:

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

Vous pouvez ajouter cela à un script et l'appeler votre "façon ninja", car si rien ne répond à vos besoins, vous pouvez le construire :-)

m3nda
la source
Ou, utilisez simplement l' -noption de split.
Amit Naidu
8

vous pouvez également utiliser awk

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

HDFS getmerge petit fichier et déversé dans la taille de la propriété.

Cette méthode provoquera un saut de ligne

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

J'essaie d'obtenir et de diviser en environ 128 Mo chaque fichier.

# 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
la source