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