J'ai un fichier avec -|
comme séparateur après chaque section ... nécessité de créer des fichiers séparés pour chaque section en utilisant Unix.
exemple de fichier d'entrée
wertretr
ewretrtret
1212132323
000232
-|
ereteertetet
232434234
erewesdfsfsfs
0234342343
-|
jdhg3875jdfsgfd
sjdhfdbfjds
347674657435
-|
Résultat attendu dans le fichier 1
wertretr
ewretrtret
1212132323
000232
-|
Résultat attendu dans le fichier 2
ereteertetet
232434234
erewesdfsfsfs
0234342343
-|
Résultat attendu dans le fichier 3
jdhg3875jdfsgfd
sjdhfdbfjds
347674657435
-|
Un seul paquebot, pas de programmation. (sauf l'expression rationnelle, etc.)
csplit --digits=2 --quiet --prefix=outfile infile "/-|/+1" "{*}"
awk '{print $0 " -|"> "file" NR}' RS='-\\|' input-file
Explication (édité):
RS
est le séparateur d’enregistrements et cette solution utilise une extension gnu awk qui lui permet d’avoir plus d’un caractère. NR
est le numéro d'enregistrement.
L'instruction print imprime un enregistrement suivi de " -|"
dans un fichier contenant le numéro d'enregistrement dans son nom.
Debian a csplit
, mais je ne sais pas si cela est commun à toutes/la plupart/d'autres distributions. Sinon, il ne devrait pas être trop difficile de localiser la source et de la compiler ...
J'ai résolu un problème légèrement différent, où le fichier contient une ligne avec le nom où le texte qui suit doit être placé. Ce code Perl fait le tour pour moi:
#!/path/to/Perl -w
#comment the line below for UNIX systems
use Win32::Clipboard;
# Get command line flags
#print ($#ARGV, "\n");
if($#ARGV == 0) {
print STDERR "usage: ncsplit.pl --mff -- filename.txt [...] \n\nNote that no space is allowed between the '--' and the related parameter.\n\nThe mff is found on a line followed by a filename. All of the contents of filename.txt are written to that file until another mff is found.\n";
exit;
}
# this package sets the ARGV count variable to -1;
use Getopt::Long;
my $mff = "";
GetOptions('mff' => \$mff);
# set a default $mff variable
if ($mff eq "") {$mff = "-#-"};
print ("using file switch=", $mff, "\n\n");
while($_ = shift @ARGV) {
if(-f "$_") {
Push @filelist, $_;
}
}
# Could be more than one file name on the command line,
# but this version throws away the subsequent ones.
$readfile = $filelist[0];
open SOURCEFILE, "<$readfile" or die "File not found...\n\n";
#print SOURCEFILE;
while (<SOURCEFILE>) {
/^$mff (.*$)/o;
$outname = $1;
# print $outname;
# print "right is: $1 \n";
if (/^$mff /) {
open OUTFILE, ">$outname" ;
print "opened $outname\n";
}
else {print OUTFILE "$_"};
}
Vous pouvez également utiliser awk. Je ne connais pas très bien awk, mais ce qui suit a semblé fonctionner pour moi. Il a généré part1.txt, part2.txt, part3.txt et part4.txt. Notez que le dernier fichier partn.txt que cela génère est vide. Je ne sais pas comment résoudre ce problème, mais je suis sûr que cela pourrait être fait avec un peu de peaufinage. Des suggestions quelqu'un?
Fichier awk_pattern:
BEGIN{ fn = "part1.txt"; n = 1 }
{
print > fn
if (substr($0,1,2) == "-|") {
close (fn)
n++
fn = "part" n ".txt"
}
}
commande bash:
awk -f awk_pattern input.file
Utilisez csplit
si vous en avez.
Si vous ne le faites pas, mais que vous avez Python ... n'utilisez pas Perl.
Votre fichier est peut-être trop volumineux pour pouvoir être conservé en mémoire en une seule fois - la lecture ligne par ligne peut être préférable. Supposons que le fichier d'entrée s'appelle "samplein":
$ python3 -c "from itertools import count
with open('samplein') as file:
for i in count():
firstline = next(file, None)
if firstline is None:
break
with open(f'out{i}', 'w') as out:
out.write(firstline)
for line in file:
out.write(line)
if line == '-|\n':
break"
La commande suivante fonctionne pour moi. J'espère que ça aide.
awk 'BEGIN{file = 0; filename = "output_" file ".txt"}
/-|/ {getline; file ++; filename = "output_" file ".txt"}
{print $0 > filename}' input
Voici un script Python 3 qui divise un fichier en plusieurs fichiers en fonction d'un nom de fichier fourni par les délimiteurs. Exemple de fichier d'entrée:
# Ignored
######## FILTER BEGIN foo.conf
This goes in foo.conf.
######## FILTER END
# Ignored
######## FILTER BEGIN bar.conf
This goes in bar.conf.
######## FILTER END
Voici le script:
#!/usr/bin/env python3
import os
import argparse
# global settings
start_delimiter = '######## FILTER BEGIN'
end_delimiter = '######## FILTER END'
# parse command line arguments
parser = argparse.ArgumentParser()
parser.add_argument("-i", "--input-file", required=True, help="input filename")
parser.add_argument("-o", "--output-dir", required=True, help="output directory")
args = parser.parse_args()
# read the input file
with open(args.input_file, 'r') as input_file:
input_data = input_file.read()
# iterate through the input data by line
input_lines = input_data.splitlines()
while input_lines:
# discard lines until the next start delimiter
while input_lines and not input_lines[0].startswith(start_delimiter):
input_lines.pop(0)
# corner case: no delimiter found and no more lines left
if not input_lines:
break
# extract the output filename from the start delimiter
output_filename = input_lines.pop(0).replace(start_delimiter, "").strip()
output_path = os.path.join(args.output_dir, output_filename)
# open the output file
print("extracting file: {0}".format(output_path))
with open(output_path, 'w') as output_file:
# while we have lines left and they don't match the end delimiter
while input_lines and not input_lines[0].startswith(end_delimiter):
output_file.write("{0}\n".format(input_lines.pop(0)))
# remove end delimiter if present
if not input_lines:
input_lines.pop(0)
Enfin voici comment vous l'exécutez:
$ python3 script.py -i input-file.txt -o ./output-folder/
Voici un code Perl qui fera l'affaire
#!/usr/bin/Perl
open(FI,"file.txt") or die "Input file not found";
$cur=0;
open(FO,">res.$cur.txt") or die "Cannot open output file $cur";
while(<FI>)
{
print FO $_;
if(/^-\|/)
{
close(FO);
$cur++;
open(FO,">res.$cur.txt") or die "Cannot open output file $cur"
}
}
close(FO);
cat file| ( I=0; echo -n "">file0; while read line; do echo $line >> file$I; if [ "$line" == '-|' ]; then I=$[I+1]; echo -n "" > file$I; fi; done )
et la version formatée:
#!/bin/bash
cat FILE | (
I=0;
echo -n"">file0;
while read line;
do
echo $line >> file$I;
if [ "$line" == '-|' ];
then I=$[I+1];
echo -n "" > file$I;
fi;
done;
)