web-dev-qa-db-fra.com

Fractionner un fichier texte volumineux sur chaque ligne vierge

J'ai un peu de mal à diviser un fichier texte volumineux en plusieurs fichiers plus petits. La syntaxe de mon fichier texte est la suivante:

dasdas #42319 blaablaa 50 50
content content
more content
content conclusion

asdasd #92012 blaablaa 30 70
content again
more of it
content conclusion

asdasd #299 yadayada 60 40
content
content
contend done
...and so on

(dasdas # 42319 blaablaa 50 50, contenu de contenu, plus de contenu et conclusion de contenu sont leurs propres lignes séparées suivies d'une ligne vide est la fin de cette table d'informations. Une table d'informations typique dans mon fichier contient entre 10 et 40 lignes. )

Je voudrais que ce fichier soit divisé en n fichiers plus petits, où n est la quantité de tables de contenu.
C'est

dasdas #42319 blaablaa 50 50
content content
more content
content conclusion

serait son propre fichier séparé, (WhateverN.txt)

et

asdasd #92012 blaablaa 30 70
content again
more of it
content conclusion

à nouveau un fichier séparé quels que soient N + 1.txt et ainsi de suite.

Il semble que awk ou Perl soient des outils astucieux pour cela, mais ne les ayant jamais utilisées auparavant, la syntaxe est un peu déroutante.

J'ai trouvé ces deux questions qui correspondent presque à mon problème, mais je n'ai pas réussi à modifier la syntaxe pour répondre à mes besoins.

Divise un fichier texte en plusieurs fichiers &
https://unix.stackexchange.com/questions/46325/how-can-i-split-a-text-file-int-multiple-text-files

Comment faut-il modifier les entrées de ligne de commande pour résoudre mon problème?

12
tropical e

Définir RS sur null indique à awk d'utiliser une ou plusieurs lignes vides comme séparateur d'enregistrement. Ensuite, vous pouvez simplement utiliser NR pour définir le nom du fichier correspondant à chaque nouvel enregistrement:

 awk -v RS= '{print > ("whatever-" NR ".txt")}' file.txt

RS: Ceci est le séparateur d'enregistrement d'entrée de awk. Sa valeur par défaut est une chaîne contenant un seul caractère de nouvelle ligne, ce qui signifie qu'un enregistrement d'entrée est constitué d'une seule ligne de texte. Il peut également s'agir d'une chaîne nulle, auquel cas les enregistrements sont séparés par des suites de lignes vides , ou d'une expression rationnelle, auquel cas les enregistrements sont séparés par des correspondances de l'expression rationnelle figurant dans le texte saisi.

$ cat file.txt
dasdas #42319 blaablaa 50 50
content content
more content
content conclusion

asdasd #92012 blaablaa 30 70
content again
more of it
content conclusion

asdasd #299 yadayada 60 40
content
content
contend done

$ awk -v RS= '{print > ("whatever-" NR ".txt")}' file.txt

$ ls whatever-*.txt
whatever-1.txt  whatever-2.txt  whatever-3.txt

$ cat whatever-1.txt 
dasdas #42319 blaablaa 50 50
content content
more content
content conclusion

$ cat whatever-2.txt 
asdasd #92012 blaablaa 30 70
content again
more of it
content conclusion

$ cat whatever-3.txt 
asdasd #299 yadayada 60 40
content
content
contend done
$ 
20
jas

Perl a une fonctionnalité utile appelée le séparateur d'enregistrement d'entrée. $/.

C'est le "marqueur" pour séparer les enregistrements lors de la lecture d'un fichier.

Alors:

#!/usr/bin/env Perl
use strict;
use warnings;

local $/ = "\n\n"; 
my $count = 0; 

while ( my $chunk = <> ) {
    open ( my $output, '>', "filename_".$count++ ) or die $!;
    print {$output} $chunk;
    close ( $output ); 
}

Juste comme ça. Le <> est le descripteur de fichier 'magique', dans la mesure où il lit les données transférées ou à partir de fichiers spécifiés sur la ligne de commande (les ouvre et les lit). Ceci est similaire au fonctionnement de sed ou grep.

Ceci peut être réduit à une seule ligne:

Perl -00 -pe 'open ( $out, '>', "filename_".++$n ); select $out;'  yourfilename_here
3
Sobrique

Vous pouvez utiliser cette awk,

awk 'BEGIN{file="content"++i".txt"} !NF{file="content"++i".txt";next} {print > file}' yourfile

(OU)

awk 'BEGIN{i++} !NF{++i;next} {print > "filename"i".txt"}' yourfile

Format plus lisible:

BEGIN {
        file="content"++i".txt"
}
!NF {
        file="content"++i".txt";
        next
}
{
        print > file
}
2
sat

Comme c'est vendredi et que je me sens un peu utile ... :)

Essaye ça. Si le fichier est aussi petit que vous l'imaginez, il est plus simple de simplement le lire en une fois et de travailler en mémoire.

use strict;
use warnings;

# Slurp file
local $/ = undef;
open my $fh, '<', 'test.txt' or die $!;
my $text = <$fh>;
close $fh;

# split on double new line
my @chunks = split(/\n\n/, $text);

# make new files from chunks
my $count = 1;
for my $chunk (@chunks) {
    open my $ofh, '>', "whatever$count.txt" or die $!;
    print $ofh $chunk, "\n";
    close $ofh;
    $count++;
}

La documentation Perl peut expliquer toutes les commandes individuelles que vous ne comprenez pas, mais à ce stade, vous devriez probablement également consulter un didacticiel.

0
Nick P

Essayez aussi ce script bash

#!/bin/bash
i=1
fileName="OutputFile_$i"
while read line ; do 
if [ "$line"  == ""  ] ; then
 ((++i))
 fileName="OutputFile_$i"
else
 echo $line >> "$fileName"
fi
done < InputFile.txt
0
Kalanidhi
awk -v RS="\n\n" '{for (i=1;i<=NR;i++); print > i-1}' file.txt

Définit le séparateur d’enregistrement en tant que ligne vierge, imprime chaque enregistrement en tant que fichier séparé numéroté 1, 2, 3, etc. Le dernier fichier (uniquement) se termine par une ligne vierge.

0
user2138595