web-dev-qa-db-fra.com

Comment diviser un fichier en parties égales sans rompre les lignes?

Je me demandais s'il était possible de diviser un fichier en parties égales (edit: = tous égaux sauf le dernier), sans rompre la ligne? En utilisant la commande split sous Unix, les lignes peuvent être divisées en deux. Existe-t-il un moyen, par exemple, de scinder un fichier en 5 parties égales, mais de ne le garder que sous forme de lignes entières (aucun problème si l’un des fichiers est un peu plus gros ou plus petit)? Je sais que je pourrais simplement calculer le nombre de lignes, mais je dois le faire pour beaucoup de fichiers dans un script bash. Merci beaucoup!

99
Abdel

Si vous voulez dire un nombre égal de lignes, split a une option pour cela:

split --lines=75

Si vous avez besoin de savoir ce que cela 75 devrait vraiment être pour N parts égales, c'est:

lines_per_part = int(total_lines + N - 1) / N

où le nombre total de lignes peut être obtenu avec wc -l.

Voir le script suivant pour un exemple:

#!/usr/bin/bash

# Configuration stuff

fspec=qq.c
num_files=6

# Work out lines per file.

total_lines=$(wc -l <${fspec})
((lines_per_file = (total_lines + num_files - 1) / num_files))

# Split the actual file, maintaining lines.

split --lines=${lines_per_file} ${fspec} xyzzy.

# Debug information

echo "Total lines     = ${total_lines}"
echo "Lines  per file = ${lines_per_file}"    
wc -l xyzzy.*

Cela génère:

Total lines     = 70
Lines  per file = 12
  12 xyzzy.aa
  12 xyzzy.ab
  12 xyzzy.ac
  12 xyzzy.ad
  12 xyzzy.ae
  10 xyzzy.af
  70 total

Les versions plus récentes de split vous permettent de spécifier un nombre de CHUNKS avec le -n/--number option. Vous pouvez donc utiliser quelque chose comme:

split --number=l/6 ${fspec} xyzzy.

(c'est ell-slash-six, signifiant lines, pas one-slash-six).

Cela vous donnera à peu près les mêmes fichiers en termes de taille, sans division en milieu de ligne.

Je mentionne ce dernier point car il ne vous donne pas à peu près le même nombre de lignes dans chaque fichier, plus le même nombre de lignes caractères.

Donc, si vous avez une ligne de 20 caractères et 19 lignes de 1 caractère (vingt lignes au total) et que vous vous séparez en cinq fichiers, vous ne le ferez probablement pas obtenir quatre lignes dans chaque fichier.

135
paxdiablo

Le script n'est même pas nécessaire, split (1) supporte la fonctionnalité voulue immédiatement:
split -l 75 auth.log auth.log. _ La commande ci-dessus divise le fichier en morceaux de 75 lignes et génère le fichier sous la forme: auth.log.aa, auth.log.ab, ...

wc -l sur le fichier d'origine et la sortie donne:

  321 auth.log
   75 auth.log.aa
   75 auth.log.ab
   75 auth.log.ac
   75 auth.log.ad
   21 auth.log.ae
  642 total
38
jbr

split a été mis à jour dans la version 8.8 de coreutils (annoncée le 22 décembre 2010) avec l'option --number pour générer un nombre spécifique de fichiers. L'option --number = l/n génère n fichiers sans fractionner les lignes.

http://www.gnu.org/software/coreutils/manual/html_node/split-invocation.html#split-invocationhttp://savannah.gnu.org/forum/ forum.php? forum_id = 6662

20
user3769065

Une solution simple pour une question simple:

split -n l/5 your_file.txt

pas besoin de script ici.

Dans le fichier man , CHUNKS may be:

l/N     split into N files without splitting lines

Mettre à jour

Toutes les distributions Unix n'incluent pas ce drapeau. Par exemple, cela ne fonctionnera pas sous OSX. Pour l'utiliser, vous pouvez envisager en remplaçant les utilitaires Mac OS X par GNU) .

15
Kuf

J'ai fait un script bash, qui donne un certain nombre de parties en entrée, divise un fichier

#!/bin/sh

parts_total="$2";
input="$1";

parts=$((parts_total))
for i in $(seq 0 $((parts_total-2))); do
  lines=$(wc -l "$input" | cut -f 1 -d" ")
  #n is rounded, 1.3 to 2, 1.6 to 2, 1 to 1
  n=$(awk  -v lines=$lines -v parts=$parts 'BEGIN { 
    n = lines/parts;
    rounded = sprintf("%.0f", n);
    if(n>rounded){
      print rounded + 1;
    }else{
      print rounded;
    }
  }');
  head -$n "$input" > split${i}
  tail -$((lines-n)) "$input" > .tmp${i}
  input=".tmp${i}"
  parts=$((parts-1));
done
mv .tmp$((parts_total-2)) split$((parts_total-1))
rm .tmp*

J'ai utilisé les commandes head et tail, et les ai stockées dans des fichiers tmp, pour scinder les fichiers

#10 means 10 parts
sh mysplitXparts.sh input_file 10

ou avec awk, où 0.1 est 10% => 10 parties, ou 0.334 est 3 parties

awk -v size=$(wc -l < input) -v perc=0.1 '{
  nfile = int(NR/(size*perc)); 
  if(nfile >= 1/perc){
    nfile--;
  } 
  print > "split_"nfile
}' input
var dict = File.ReadLines("test.txt")
               .Where(line => !string.IsNullOrWhitespace(line))
               .Select(line => line.Split(new char[] { '=' }, 2, 0))
               .ToDictionary(parts => parts[0], parts => parts[1]);


or 

    enter code here

line="[email protected][email protected]";
string[] tokens = line.Split(new char[] { '=' }, 2, 0);

ans:
tokens[0]=to
token[1][email protected][email protected]"
1
Prabu