J'ai un vidage d'e-mail d'environ 400 Mo. Je veux diviser cela en fichiers .txt, consistant en un mail dans chaque fichier. Chaque e-mail commence par l'en-tête HTML standard spécifiant le doctype.
Cela signifie que je devrai diviser mes fichiers en fonction de l'en-tête susmentionné. Comment puis-je m'y prendre sous Linux?
Si tu as un mail.txt
$ cat mail.txt
<html>
mail A
</html>
<html>
mail B
</html>
<html>
mail C
</html>
exécutez csplit
pour diviser par <html>
$ csplit mail.txt '/^<html>$/' '{*}'
- mail.txt => input file
- /^<html>$/ => pattern match every `<html>` line
- {*} => repeat the previous pattern as many times as possible
vérifier la sortie
$ ls
mail.txt xx00 xx01 xx02 xx03
Si vous voulez le faire dans awk
$ awk '/<html>/{filename=NR".txt"}; {print >filename}' mail.txt
$ ls
1.txt 5.txt 9.txt mail.txt
Le programme csplit
résout votre problème avec élégance:
csplit '/<!DOCTYPE.*/' $FILE
csplit
est la meilleure solution à ce problème. Je pensais juste publier une solution bash pour montrer qu'il n'est pas nécessaire d'aller Perl dans cette tâche:
#!/usr/bin/bash
MAIL='mail' # path to huge mail-file
#get linenumbers for all headers
line_no=$(grep -n html $MAIL | cut -d: -f1)
read -a LINES<<< $line_no
file=0
for i in $(seq 0 2 ${#LINES[@]}); do
start=${LINES[i]}
end=$((${LINES[i+1]}-1))
echo $start, $end
sed -n "${start},${end}p" $MAIL > ${MAIL}${file}.txt
file=$((file+1))
done
C'est faisable avec un peu de "magie" de Perl ... Beaucoup de gens diraient que c'est moche, mais voilà.
L'astuce consiste à remplacer $/
avec ce que vous voulez et lisez votre entrée, en tant que telle:
#!/usr/bin/Perl -W
use strict;
my $i = 1;
$/ = <<EOF;
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html><head> <xmeta content="text/html;charset=ISO-8859-1" http-equiv="Content-Type">
EOF
open INPUT, "/path/to/inputfile" or die;
while (my $mail = <INPUT>) {
$mail = substr($mail, 0, index($mail, $/));
open OUTPUT, ">/path/to/emailfile." . $i . ".txt" or die;
$i++;
print OUTPUT $mail;
close OUTPUT;
}
edit: fixe, j'oublie toujours que $/
est inclus dans l'entrée. De plus, le premier fichier sera toujours vide, mais il pourra alors être facilement manipulé.
Je suis d'accord avec fge. Avec Perl
, ce serait beaucoup plus simple. Vous pouvez essayer quelque chose comme ça -
#!/usr/bin/Perl
undef $/;
$_ = <>;
$n = 0;
for $match (split(/(?=HEADER_FORMAT)/)) {
open(O, '>mail' . ++$n);
print O $match;
close(O);
}
Remplacer HEADER_FORMAT
avec votre type d'en-tête.