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 XYZ
tel qu'il file1
contient des lignes vers le haut XYZ
et 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 XYZ
tel qu'il file1
contient des lignes vers le haut XYZ
et le reste des lignes file2
.
Réponses:
Avec awk
vous pouvez faire:
awk '{print >out}; /XYZ/{out="file2"}' out=file1 largefile
Explication: Le premier awk
argument ( out=file1
) définit une variable avec le nom de fichier qui sera utilisé pour la sortie pendant le largefile
traitement de l' argument suivant ( ). Le awk
programme imprimera toutes les lignes dans le fichier spécifié par la variable out
( {print >out}
). Si le motif XYZ
est 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 s
ilently diviser le fichier, la création de pièces avec pré f
ix file
et n
umbered à l' aide d' un seul chiffre, par exemple , file0
etc. 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 regex
ajouter un +1
décalage:
csplit -sf file -n 1 large_file /XYZ/+1
Cela crée deux fichiers file0
et file1
. Si vous avez absolument besoin qu'ils soient nommés file1
et que file2
vous puissiez toujours ajouter un modèle vide à la csplit
commande et supprimer le premier fichier:
csplit -sf file -n 1 large_file // /XYZ/+1
crée file0
, file1
et file2
mais file0
est vide de sorte que vous pouvez en toute sécurité supprimer:
rm -f file0
Avec une version moderne, ksh
voici une variante de shell (c'est-à-dire sans sed
) de l'une des sed
réponses ci-dessus:
{ read in <##XYZ ; print "$in" ; cat >file2 ;} <largefile >file1
Et une autre variante en elle- ksh
même (c'est-à-dire en omettant également la cat
):
{ read in <##XYZ ; print "$in" ; { read <##"" ;} >file2 ;} <largefile >file1
(La ksh
solution 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
).
read
et 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 ksh
compilez tous les buildins - c'est bizarre pour moi que ce sed
ne soit pas l'un d'eux, en fait. Mais avec des trucs comme while <file do
je suppose que vous n'avez pas besoin de sed
tant de choses ...
awk
avez-vous performé dans votre benchmark? Et même si je suis sûr que vous ksh
gagnerez probablement toujours ce combat, si vous utilisez un GNU, sed
vous n'êtes pas très juste sed
- GNU's -u
nbuffered 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 sed
devrait 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 while
boucle je pense être important plus lent (mais n'ai pas vérifié).
head
au 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é f
et les deux fichiers de sortie f1
et 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>f2
Y compris la ligne assortie:
perl -ne '$a=1 if /XYZ/; $a==1 ? print STDERR : print STDOUT;' f >f1 2>f2
Vous 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 "$_";' f
Y compris la ligne assortie:
perl -ne 'BEGIN{open($fh1,">","f1"); open($fh2,">","f2");}
$a=1 if /XYZ/; $a==1 ? print $fh1 "$_" : print $fh2 "$_";' f
XYZ
ligne doit-elle être incluse ou non dans la sortie?