Retourner aux forums || Retourner au forum Programmation.shell
Programmation.shell : Suppression massive de lignes
Posté par TuxPierre () le 26 janvier 2007Voila je cherche un petit conseil. Je possede deux fichiers: f1 et f2 (environ 100000 et 60000 lignes respectivement).
Ce que je souhaite faire c'est supprimer de f1 les entrees se trouvant dans f2. A priori facile.. mais ce que je cherche c'est la solution la plus rapide possible.
Pour l'instant je parcours mon fichier f2 et je fais un sed '/entre/d' f1. Ca marche mais c'est terriblement lent..
J'ai essaye un grep -v -f f2 f1mais c'est encore pire.
Alors si qqn a une idee, je suis preneur.
Petite precision, les fichiers f1 et f2 ne contiennent pas les memes donnees.
Merci
> Lire le message (19 commentaires, moyenne: 1,6).
fichier trié ?
Tes fichiers sont trié ? Sinon, pour chaque ligne de f1 tu dois tester avec tout f2.
Sinon, il faut avancer les 2 fichiers ensembles.
-
[^]Re: fichier trié ?
Posté par TuxPierre () le 26/01/2007 à 10:56. (lien). Évalué à 1.Effectivement mes fichiers sont non tries.
En fait f1 contient pas mal d'infos (genre: cle blablabla) et f2 ne contient que des "cles" (une par ligne).
Donc je suis effectivement oblige de parcourir tout f2 (je pense..)-
[^]Re: fichier trié ?
Posté par Nicolas Boulay () le 26/01/2007 à 12:17. (lien). Évalué à 2.Je ferais un parse en perl qui colle f2 dans un %hash ensuite tu cherches chaque clef de f1 dans le hash, si tu le trouve, bingo.
-
[^]Re: fichier trié ?
-
-
Capillo-tracte
Hello,
voila une idee, non testee:
concatenation des 2 fichiers
~> cat f1 f2 > f3
selection des doublons (il faut trier d'abord)
~> sort f3 > f4; uniq -d f4 > doublons
concat doublons et f1
~> cat f1 doublons > f5
selection des lignes uniques de f1 (toutes celles qui sont aussi dans f2 sont en double dans f5)
~> sort f5; uniq f5 > f6
et hop, dans f6 tu as ce que tu veux!
Je pense que ca peut etre relativement rapide.
pour rigoler, ca doit pouvoir se faire en une ligne:
~> cat f1 `cat f1 f2 | sort | uniq -d` | sort | uniq
-
[^]Re: Capillo-tracte
Posté par TuxPierre () le 26/01/2007 à 10:58. (lien). Évalué à 1.Merci de ta reponse mais je ne pense pas que ca marche.
Comme dit plus haut, les fichiers ne contiennent pas les memes donnees.
f1 contient des infos + des "cles" (ex: cle blablabla) et f2 ne contient que "des cles" (une par ligne)
Donc meme en triant je n'aurais pas de doublon..-
[^]Re: Capillo-tracte
Posté par imalip (page perso, ) le 26/01/2007 à 11:13. (lien). Évalué à 2.et un grand coup de
grep -v "^cle " f1
ca peut pas le faire, si le but est juste de virer les lignes de clef ?
hmmm... F1... RB3... désolé, je m'égare...--
"While a monkey can be a manager, it takes a human to be an engineer" Erik Zapletal
-
[^]Re: Capillo-tracte
Posté par lom (page perso, ) le 26/01/2007 à 12:11. (lien). Évalué à 1.Ah OK, j'avais effectivement mal compris... Ca ne peut pas marcher comme ca.
Desole, et bonne chance quand meme!
-
Si tu peux utiliser autre chose que le shell...
J'avais commencé par un remlines.py
#!/bin/env python
# -*- coding: ascii -*-
def remlines(fin,fref,fout) :
....lines_to_remove = set(iter(open(fref)))
....fin_file = open(fin)
....fout_file = open(fout,"w")
....for line in fin_file :
........if not line in lines_to_remove :
........fout_file.write(line)
....fout_file.close()
....fin_file.close()
if __name__ == "__main__" :
....import sys
....remlines(sys.argv[1],sys.argv[2],sys.argv[3])
(j'ai mis des . en début de ligne à la place des espaces because indentation en Python)
Qui supprime les lignes de f2 que l'on trouve exactement dans f1.
Mais j'ai vu ta petite précision les fichiers f1 et f2 ne contiennent pas les memes donnees et les discussions... bref tu recherche pour chaque ligne de f1 si elle contient une des lignes de f2... Ca serait bien le boulot d'une jolie expression régulière avec f2[0] | f2[1] | f2[3]... compilée en mémoire, et appliquée à chacune des lignes de f1. Ca peut se faire en Python (modulo peut-être la longueur d'une telle expression), mais il me semble que ce genre de traitement est le domaine naturel de Perl.
-
[^]Re: Si tu peux utiliser autre chose que le shell...
Posté par Laurent Pointal (page perso, ) le 26/01/2007 à 13:00. (lien). Évalué à 2....et si tu es capable d'extraire ta clé:
....for line in fin_file :
........if not extraction_cle(line) in lines_to_remove :
............fout_file.write(line)
[gaffe, j'avais oublié une indentation dans la ligne après celle du "if" dans mon post précédent.]
Ca correspond à la proposition qui a été fait d'utiliser un hash en Perl (là j'utilise un set en Python). Je ne pense pas que tu puisses trouver plus rapide comme algo.
Note: tout ça en considérant qu'il n'y a pas de problème de casse/marques diacritiques entre l'expression les clés dans F1 et celle dans f2.-
[^]Re: Si tu peux utiliser autre chose que le shell...
Posté par Laurent Pointal (page perso, ) le 26/01/2007 à 13:02. (lien). Évalué à 2.Pour extraction_cle, si tu poste un exemple, on pourra faire un bout de code.
-
[^]Re: Si tu peux utiliser autre chose que le shell...
Posté par TuxPierre () le 26/01/2007 à 13:36. (lien). Évalué à 1.Ok, c'est gentil.
Le fichier f1 est de la forme :
ip: blablabla
Le blabla peut etre de diverses formes.
Le fichier f2 contient une liste d'adresse ip (une par ligne)-
[^]Re: Si tu peux utiliser autre chose que le shell...
Posté par Laurent Pointal (page perso, ) le 26/01/2007 à 14:24. (lien). Évalué à 2.Ajoute la fonction suivante:
def extraction_cle(line) :
....return line.split(':')[0]
Ou bien directement dans le test:
....for line in fin_file :
........if not line.split(':')[0] in lines_to_remove :
............fout_file.write(line)
-
[^]Re: Si tu peux utiliser autre chose que le shell...
Posté par Laurent Pointal (page perso, ) le 26/01/2007 à 14:34. (lien). Évalué à 2.J'oubliais, s'il y a des problèmes de retours à la ligne qui resteraient dans les chaines suite à la lecture de f2, tu peux modifier un peu le chargement des clés:
....lines_to_remove = set( (i.strip() for i in open(fref) ) )
Note au cas où: ça s'appelle avec :
python remlines.py f1 f2 fsortie-
[^]Au final...
Posté par Laurent Pointal (page perso, ) le 26/01/2007 à 15:05. (lien). Évalué à 2.
#!/bin/env python
# -*- coding: ascii -*-
def remlines(fin,fref,fout) :
....lines_to_remove = set( (i.strip() for i in open(fref)))
....fin_file = open(fin)
....fout_file = open(fout,"w")
....for line in fin_file :
........if not line.split(':')[0] in lines_to_remove :
............fout_file.write(line)
....fout_file.close()
....fin_file.close()
if __name__ == "__main__" :
....import sys
....remlines(sys.argv[1],sys.argv[2],sys.argv[3])
J'ai essayé avec f1:
12.4.23.54: Un essai
192.168.0.1:It is bad
54.123.14.53:La y'a qq chose
127.0.0.1:A retirer
90.32.41.15:Et encore la c'est bon
255.255.255.255:Non mais ca c'est nul
32.435.124.23:Et ce c'est ok
Et f2:
192.168.0.1
127.0.0.1
255.255.255.255
python remlines.py f1 f2 fout
Dis nous ce que ça donne côté perfs sur tes gros fichiers.
-
-
-
-
-
rien à voir avec le shell mais: sql
et pourquoi pas une importation dans une base sql ?
Avec les indexes et le delete from ... where... in(select... qui vont bien, ça pourrait prendre quelques secondes.
ou encore plus jouissif, un trigger sur f2 qui détruit l'enregistrement dans f1 correspondant...
ps: recommandé pour une utilisation répétées bien sûr
-
[^]Re: rien à voir avec le shell mais: sql
Posté par TuxPierre () le 26/01/2007 à 13:33. (lien). Évalué à 1.Oh la bonne idee.. J'avoue que je n'y avais pas pense..
Apres un petit test tout bete (et deux jolis index), l'operation ne mets que 4 secondes :)
C'est extremement efficace !!!!
Merci donc de ta reponse
PS: j'utilise une base SQL pour stocker d'autres donnees donc tout va bien.. mais si je ne l'avais pas.. le pb reste entier ;)
Memory mapping
J'ai essayé un grep -v -f f2 f1mais c'est encore pire.
Et quid de l'option -mmap pour grep ? Il y avait déjà eu une astuce à ce propos: http://www.linuxfr.org/tips/269.html Cela vaut-il la peine d'être considéré ?
Certes, effectuer les traitements grâce à MySQL semble élégant et impressionnant en terme de vitesse, cependant, si l'on considère aussi l'importation des données, auparavant, le temps total pour effectuer toutes les opérations est sans doute plus long, non ?
-
[^]Re: Memory mapping
Posté par TuxPierre () le 26/01/2007 à 15:09. (lien). Évalué à 1.Je pensais la meme chose au niveau de l'import.. Mais en faisant un load data infile.. hop hop hop en moins de 2 secondes le fichier est mangé :)
Je ne connaissais pas l'option -mmap de grep mais malheureusement elle n'est pas dispo sous mon OS (OpenBSD)
Revenir en haut de page || Retourner aux forums || Retourner au forum Programmation.shell



Cette discussion est archivée, il n'est plus possible de laisser des commentaires.
Note : les commentaires appartiennent à ceux qui les ont postés. Nous n'en sommes pas responsables.