J'ai un fichier avec plus de 40 000 lignes (fichier1) et je veux extraire les lignes correspondant aux modèles du fichier2 (environ 6 000 lignes). J'utilise grep comme ça, mais c'est très lent: grep -f file2 file1 > out
Existe-t-il un moyen plus rapide de le faire en utilisant awk
ou sed
?
Voici quelques extraits de mes fichiers:
File1:
scitn003869.2| scign003869 CGCATGTGTGCATGTATTATCGTATCCCTTG
scitn007747.1| scign007747 CACGCAGACGCAGTGGAGCATTCCAGGTCACAA
scitn003155.1| scign003155 TAAAAATCGTTAGCACTCGCTTGGTACACTAAC
scitn018252.1| scign018252 CGTGTGTGTGCATATGTGTGCATGCGTG
scitn004671.2| scign004671 TCCTCAGGTTTTGAAAGGCAGGGTAAGTGCT
File2:
scign000003
scign000004
scign000005
scign004671
scign000013
"
Essayez grep -Fwf file2 file1 > out
Le -F
option spécifie la correspondance des chaînes simples, donc devrait être plus rapide sans avoir à engager le moteur d'expression régulière.
Voici comment le faire dans awk:
awk 'NR==FNR{pats[$0]; next} $2 in pats' File2 File1
En utilisant un fichier1 de 60 000 lignes (votre fichier1 a été répété 8 000 fois) et un fichier 6 0002 (le vôtre s'est répété 1 200 fois):
$ time grep -Fwf File2 File1 > ou2
real 0m0.094s
user 0m0.031s
sys 0m0.062s
$ time awk 'NR==FNR{pats[$0]; next} $2 in pats' File2 File1 > ou1
real 0m0.094s
user 0m0.015s
sys 0m0.077s
$ diff ou1 ou2
c'est-à-dire qu'il est à peu près aussi rapide que le grep. Une chose à noter cependant est que la solution awk vous permet de choisir un champ spécifique pour correspondre, donc si quelque chose de File2 apparaît ailleurs dans File1, vous n'obtiendrez pas une fausse correspondance. Il vous permet également de faire correspondre un champ entier à la fois, donc si vos chaînes cibles étaient de différentes longueurs et que vous ne vouliez pas que "scign000003" corresponde à "scign0000031" par exemple (bien que -w pour grep offre une protection similaire pour cela).
Pour être complet, voici le timing pour l'autre solution awk publiée elsethread:
$ time awk 'BEGIN{i=0}FNR==NR{a[i++]=$1;next}{for(j=0;j<i;j++)if(index($0,a[j]))print $0}' File2 File1 > ou3
real 3m34.110s
user 3m30.850s
sys 0m1.263s
et voici le timing que je reçois pour le script Perl que Mark a publié:
$ time ./go.pl > out2
real 0m0.203s
user 0m0.124s
sys 0m0.062s
Vous pouvez essayer avec cet awk:
awk 'BEGIN{i=0}
FNR==NR { a[i++]=$1; next }
{ for(j=0;j<i;j++)
if(index($0,a[j]))
{print $0;break}
}' file2 file1
Le FNR==NR
part spécifie que les éléments qui le suivent entre accolades ne doivent être appliqués que lors du traitement du premier fichier d'entrée (file2
). Et il dit de sauvegarder tous les mots que vous recherchez dans un tableau a[]
. Le bit du deuxième ensemble d'accolades s'applique au traitement du deuxième fichier ... à mesure que chaque ligne est lue, elle est comparée à tous les éléments de a[]
et le cas échéant, la ligne est imprimée. C'est tout le monde!
Juste pour le plaisir d'apprendre: je résolvais le même problème et j'ai trouvé différentes solutions (dont read $line
boucles etc ..). Quand je suis arrivé au grep
one-liner trouvé ci-dessus, j'ai quand même fini par obtenir la mauvaise sortie. Puis j'ai réalisé que mon fichier PATTERN avait 2 lignes de fin ... Alors grep
a récupéré toutes mes lignes de ma base de données. Moralité: vérifiez vos espaces/lignes de fin. De plus, la commande a été exécutée sur un ensemble de données beaucoup plus grand avec plusieurs centaines de modèles et time
ne pouvait même pas compter.
Juste pour le plaisir, voici une version Perl:
#!/usr/bin/Perl
use strict;
use warnings;
my %patterns;
my $srch;
# Open file and get patterns to search for
open(my $fh2,"<","file2")|| die "ERROR: Could not open file2";
while (<$fh2>)
{
chop;
$patterns{$_}=1;
}
# Now read data file
open(my $fh1,"<","file1")|| die "ERROR: Could not open file1";
while (<$fh1>)
{
(undef,$srch,undef)=split;
print $_ if defined $patterns{$srch};
}
Voici quelques timings, en utilisant un fichier1 de 60000 lignes et un fichier2 de 6000 lignes par méthode de création de fichier d'Ed:
time awk 'NR==FNR{pats[$0]; next} $2 in pats' file2 file1 > out
real 0m0.202s
user 0m0.197s
sys 0m0.005s
time ./go.pl > out2
real 0m0.083s
user 0m0.079s
sys 0m0.004s