11
votes

Fractionnement d'un grand fichier TXT en 200 fichiers TXT plus petits sur une regex à l'aide d'un script shell à bash

J'espère que le sujet est assez clair, je n'ai rien trouvé spécifiquement à ce sujet dans le bac précédemment demandé. J'ai essayé de la mettre en œuvre dans Perl ou Python, mais je pense que je suis peut-être trop difficile.

Y a-t-il une simple commande / pipeline shell qui scindera mon fichier 4MB .txt en fichiers SEPérer .txt, basé sur un début et finissant regex?

i Fournissez un bref échantillon du fichier ci-dessous .. Vous pouvez donc voir que chaque "histoire" commence par la phrase "x xxx documents", qui pourrait être utilisée pour diviser le fichier .

Je pense que cela devrait être facile et je serais surpris si Bash ne peut pas le faire - plus rapide que Perl / py.

Ici, il est: < Pré> xxx

Merci d'avance pour toute votre aide.

Ross


3 commentaires

Est-ce un exemple de texte nécessaire?


Veuillez éditer et supprimer environ 95% du texte de votre question.


Dupliqué possible de Split un fichier en plusieurs fichiers en fonction de Délimiter


5 Réponses :


0
votes

regex pour correspondre à "x des documents xxx" est
\ D {1,3} de \ D {1,3) Documents

ligne de lecture par ligne et commençant à écrire un nouveau fichier sur REGEX Match doit être bien.


0 commentaires

-1
votes

non testé: xxx


4 commentaires

Au fait, ce qui précède est pure bash. En outre, je suis sûr que Python ou Perl serait beaucoup plus rapide.


Pouvez-vous le faire avec CSplit? CSplit -K -Z -Z -Digits = 3 --Suffix = '% d.txt' --Prefix = fichier * .txt / 'splitontris'


@ROSSER - Il s'agit d'un candidat pour Split, ne connaissez pas la csplit


@SLN: Split est des fichiers de sortie de taille fixe plutôt que des regextes. @ROSSER: CSplit est une possibilité définitive.



1
votes

Dans quelle mesure avez-vous essayé dans Perl?

edit fort> Voici une méthode plus rapide. Il divise le fichier puis imprime les fichiers de pièces. P>

use strict;
use warnings;

open (my $masterfile, '<', 'yourfilename.txt') or die "Can't open yourfilename.txt: $!";

my $count = 1;
my $fh;

while (<$masterfile>) {
    if ( /(?<!\d)(\d+)\s*of\s*\d+\s*DOCUMENTS/ ) {
        defined $fh and close ($fh);
        open ($fh, '>', "Part$1_$count.txt") or die "Can't open Part$1_$count for  output: $!";
        $count++;
        next;
    }
    defined $fh and print $fh $_;
}
defined $fh and close ($fh);
close ($masterfile);


6 commentaires

$ Nombre est indéfini. Je soupçonne que vous vouliez dire $ CNT . En outre, la première fois que vous exécutez via la boucle $ fh est indéfinie, vous obtiendrez donc un ne peut pas utiliser une valeur non définie comme référence de symbole ERROR / AVERTISSEMENT Vous essayez de fermer $ fh .


Chemin sur ma tête à Perl - pas que je n'essaye pas ... Perl, Python, R, Bits de Ruby, Bash, un peu C ++. En plus d'être un médecin d'emploi et d'essayer de faire des recherches ... TA pour l'aide.


Pourrait aussi bien mettre un chèque sur la fin de la fin finale () aussi


@ROSSER - Oh, ce n'est pas si mal à Perl. Une version rasée peut être effectuée à partir de la ligne de commande, une soi-disant 1 revêtement.


Impossible d'utiliser une valeur non définie comme référence de symbole sur getfile.pl Line 16, <$ Masterfile> Ligne 1.


@Rosser - bonne prise! Votre droite, savez-vous comment le réparer? Défini $ FH et Imprimer $ FH $ _; C'était juste un exemple non testé, c'est fixé maintenant. Je l'écrirais probablement différemment pour mon usage.



22
votes
#!/usr/bin/env ruby
g=1
f=File.open(g.to_s + ".txt","w")
open("file").each do |line|
  if line[/\d+ of \d+ DOCUMENTS/]
    f.close
    g+=1
    f=File.open(g.to_s + ".txt","w")
  end
  f.print line
end

3 commentaires

Oh et nous avons un gagnant ... Vitesse et Elegance J'ai passé un été vraiment humide en 1997 avec le livre O'Reilly Sed / Awk. J'aimerais pouvoir me rappeler tout cela maintenant. Je va aller et l'obtenir TMRW. merci


Cette solution met la ligne de correspondance dans le nouveau fichier, qui répond à la question. Mais si, comme moi, vous voulez mettre la ligne correspondante dans l'ancien fichier avant de commencer le nouveau, vous feriez ceci: awk '{imprimer $ 0> n ".txt"} / texte à correspondre / { n ++}


Remarque: sur Mac OS X, vous avez besoin GAWK de par exemple. Macports pour cela pour travailler



10
votes

Comme suggéré dans d'autres solutions, vous pouvez utiliser csplit code> pour celui-ci:

csplit csplit.test '/^\.\.\./' '{*}' && sed -i '/^\.\.\./d' xx*


1 commentaires

Je ne peux pas essayer maintenant car sur Windows, mais la page de l'homme de Csplit semble suggérer d'utiliser% REGEX% au lieu de / regex / pour cela: / Regexp / [décalage] Copie jusqu'à mais non inclure une ligne de correspondance% REGEXP% [Décalage ] Passer à, mais pas inclure une ligne de correspondance