Comment diviser un gros fichier en deux parties, selon un modèle?
Donné un exemple file.txt:
ABC
EFG
XYZ
HIJ
KNL
Je veux diviser ce fichier en XYZtel qu'il file1contient des lignes vers le haut XYZet le reste des lignes file2.
Comment diviser un gros fichier en deux parties, selon un modèle?
Donné un exemple file.txt:
ABC
EFG
XYZ
HIJ
KNL
Je veux diviser ce fichier en XYZtel qu'il file1contient des lignes vers le haut XYZet le reste des lignes file2.
Réponses:
Avec awkvous pouvez faire:
awk '{print >out}; /XYZ/{out="file2"}' out=file1 largefile
Explication: Le premier awkargument ( out=file1) définit une variable avec le nom de fichier qui sera utilisé pour la sortie pendant le largefiletraitement de l' argument suivant ( ). Le awkprogramme imprimera toutes les lignes dans le fichier spécifié par la variable out( {print >out}). Si le motif XYZest trouvé, la variable de sortie sera redéfinie pour pointer vers le nouveau fichier ( {out="file2}") qui sera utilisé comme cible pour imprimer les lignes de données suivantes.
Les références:
C'est un travail pour csplit:
csplit -sf file -n 1 large_file /XYZ/
serait silently diviser le fichier, la création de pièces avec pré fix fileet numbered à l' aide d' un seul chiffre, par exemple , file0etc. Notez que l' utilisation /regex/décomposerait, mais ne comprenant pas la ligne qui correspond regex. Pour diviser jusqu'à et y compris la mise en correspondance de ligne regexajouter un +1décalage:
csplit -sf file -n 1 large_file /XYZ/+1
Cela crée deux fichiers file0et file1. Si vous avez absolument besoin qu'ils soient nommés file1et que file2vous puissiez toujours ajouter un modèle vide à la csplitcommande et supprimer le premier fichier:
csplit -sf file -n 1 large_file // /XYZ/+1
crée file0, file1et file2mais file0est vide de sorte que vous pouvez en toute sécurité supprimer:
rm -f file0
Avec une version moderne, kshvoici une variante de shell (c'est-à-dire sans sed) de l'une des sedréponses ci-dessus:
{ read in <##XYZ ; print "$in" ; cat >file2 ;} <largefile >file1
Et une autre variante en elle- kshmême (c'est-à-dire en omettant également la cat):
{ read in <##XYZ ; print "$in" ; { read <##"" ;} >file2 ;} <largefile >file1
(La kshsolution pure semble être assez performante; sur un fichier de test de 2,4 Go, elle a nécessité 19 à 21 secondes, contre 39 à 47 secondes avec l' approche sed/ cat).
readet print- vous devriez simplement le laisser aller à la sortie qui lui est propre. Les performances s'améliorent si vous construisez entièrement la boîte à outils AST et kshcompilez tous les buildins - c'est bizarre pour moi que ce sedne soit pas l'un d'eux, en fait. Mais avec des trucs comme while <file doje suppose que vous n'avez pas besoin de sedtant de choses ...
awkavez-vous performé dans votre benchmark? Et même si je suis sûr que vous kshgagnerez probablement toujours ce combat, si vous utilisez un GNU, sedvous n'êtes pas très juste sed- GNU's -unbuffered est une approche pauvre en pisse pour s'assurer POSIXLY que le décalage du descripteur est laissé là où le programme s'est arrêté. il - il ne devrait pas être nécessaire de ralentir le fonctionnement régulier du programme - la mise en mémoire tampon est très bien - tout seddevrait avoir à faire est de chercher le descripteur une fois terminé. Pour une raison quelconque, GNU renverse cette mentalité.
while; l'impression est implicitement effectuée comme l'effet secondaire défini de l' <##opérateur de redirection. Et seule la ligne correspondante doit être imprimée. ( De cette façon , la mise en œuvre de fonction de coque est plus flexible pour le soutien de incl./excl.) Une explicite whileboucle je pense être important plus lent (mais n'ai pas vérifié).
headau lieu du read; il semble un peu plus lent, mais il code terser: { head -1 <##XYZ ; { read <##"" ;} >file4 ;} <largefile >file3.
Essayez ceci avec GNU sed:
sed -n -e '1,/XYZ/w file1' -e '/XYZ/,${/XYZ/d;w file2' -e '}' large_file
sed -e '1,/XYZ/{w file1' -e 'd}' large_file > file2
Un hack facile consiste à imprimer sur STDOUT ou STDERR, selon que le motif cible a été mis en correspondance. Vous pouvez ensuite utiliser les opérateurs de redirection du shell pour rediriger la sortie en conséquence. Par exemple, en Perl, en supposant que le fichier d'entrée est appelé fet les deux fichiers de sortie f1et f2:
Supprimer la ligne qui correspond au modèle de fractionnement:
perl -ne 'if(/XYZ/){$a=1; next} ; $a==1 ? print STDERR : print STDOUT;' f >f1 2>f2Y compris la ligne assortie:
perl -ne '$a=1 if /XYZ/; $a==1 ? print STDERR : print STDOUT;' f >f1 2>f2Vous pouvez également imprimer dans différentes poignées de fichier:
Supprimer la ligne qui correspond au modèle de fractionnement:
perl -ne 'BEGIN{open($fh1,">","f1");open($fh2,">","f2");}
if(/XYZ/){$a=1; next}$a==1 ? print $fh1 "$_" : print $fh2 "$_";' fY compris la ligne assortie:
perl -ne 'BEGIN{open($fh1,">","f1"); open($fh2,">","f2");}
$a=1 if /XYZ/; $a==1 ? print $fh1 "$_" : print $fh2 "$_";' f
XYZligne doit-elle être incluse ou non dans la sortie?