IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Shell et commandes GNU Discussion :

Améliorer un grep


Sujet :

Shell et commandes GNU

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Invité
    Invité(e)
    Par défaut Améliorer un grep
    Bonjour,

    Je cherche à améliorer un script shell pour qu'il soit plus rapide (actuellement il met entre 10 et 45 minutes pour tourner). C'est la commande grep qui fait perdre le plus de temps (car les fichiers sont très gros)
    Donc je viens de faire des tests avec le fichier "fichier_test" qui ne fait que 16700 lignes (c'est loin de la taille des fichiers réels)

    J'utilisais la commande suivante pour ne récupérer que les lignes ne commençant pas par un chiffre et ne faisant que 11 caractères :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    time grep -v ^[0-9] fichier_test | grep ^...........$
    real    0m16.276s
    user    0m16.239s
    sys     0m0.030s
    Comme finalement les lignes commencent normalement par une lettre j'ai testé cette commande (c'est beaucoup mieux)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    time grep -i ^[a-z] fichier_test | grep ^...........$
    real    0m4.818s
    user    0m4.789s
    sys     0m0.046s
    J'ai aussi testé un grep équivalent sans ignorer la casse (gain de 0.3 secondes)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    time grep ^[A-Za-z] fichier_test | grep ^...........$
    real    0m4.553s
    user    0m4.539s
    sys     0m0.030s
    Ou simplement les lignes de 11 caractères :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    time grep ^...........$ fichier_test
    real    0m4.618s
    user    0m4.617s
    sys     0m0.015s
    J'ai aussi testé en recherchant directement les lignes commençant par le résultat des tests. Je passe alors de plus de 4,5 secondes à 0,1 seconde
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    time grep -E "^ABCD|^EFGH" fichier_test | grep ^...........$
    real    0m0.100s
    user    0m0.123s
    sys     0m0.015s
    J'ai donc testé la recherche d'une ligne commençant par une lettre en les listant toutes. C'est ce qui me donne le résultat le plus performant.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    grep -E "^A|^B|^C|^D|^E|^F|^G|^H|^I|^J|^K|^L|^M|^N|^O|^P|^Q|^R|^S|^T|^U|^V|^W|^X|^Y|^Z|^a|^b|^c|^d|^e|^f|^g|^h|^i|^j|^k|^l|^m|^n|^o|^p|^q|^r|^s|^t|^u|^v|^w|^x|^y|^z" fichier_test | grep ^...........$
    real    0m0.108s
    user    0m0.108s
    sys     0m0.030s
    Pourquoi il y a-t-il temps de différence entre ces différentes commandes ?

    Au final, je pense partir sur la commande sed :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    time sed -n '/^...........$/p' fichier_test
    real    0m0.106s
    user    0m0.078s
    sys     0m0.030s
    Elle semble légèrement plus rapide que la commande awk
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    time awk '/^...........$/ { print }' fichier_test
    real    0m0.110s
    user    0m0.093s
    sys     0m0.030s
    Merci

    ps: en tout cas, ça va faire un gros coup de boost dans les performances du scripts (16 secondes => 0,1 secondes pour un "petit" fichier).

  2. #2
    Expert confirmé Avatar de disedorgue
    Homme Profil pro
    Ingénieur intégration
    Inscrit en
    Décembre 2012
    Messages
    4 349
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur intégration
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Décembre 2012
    Messages : 4 349
    Par défaut
    Bonjour,

    Cette grande différence de temps doit, je pense, être liée à la proportion du type de données présente dans ton fichier.
    A priori, ton besoin précis pour le petit fichier que tu as utilisé dans tes tests, est d'avoir une ligne de 11 caractères commençant par soit A ou E.
    Donc par exemple, quand tu demandes '^[A-Z]', il va au plus faire 5 comparaisons pour valider la ligne, si la ligne est fausse, il fera la totalité des comparaisons.

    Sinon, as-tu essayé coté awk:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    awk 'length == 11' fichier
    Ou en perl (qui donne souvent de meilleur résultat que awk):
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    perl -n -e 'length == 12 && print' fichier
    Ici, on met 12 au lieu de 11 car il faut compter le retour à la ligne.

  3. #3
    Invité
    Invité(e)
    Par défaut
    Merci, le awk est plus rapide avec le length (aussi rapide que le sed):
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    time awk 'length == 11' fichier_test
    real    0m0.104s
    user    0m0.078s
    sys     0m0.045s
    Donc je pense que je vais l'utiliser. Il pourra me servir pour passer une commande supplémentaire pour modifier la ligne


    Le fichier est formé comme ci-dessous (le ligne de 11 caractères peuvent commencer par n'importe quelle lettre). Il y a plus de 90% de ligne commençant par un chiffre
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    INFO......................................................
    ABCD.......
    00........................................................
    01........................................................
    05........................................................
    10........................................................
    20........................................................
    99........................................................
    EFGH.......
    00........................................................
    01........................................................
    05........................................................
    10........................................................
    20........................................................
    99........................................................
    IJKL.......
    00........................................................
    01........................................................
    05........................................................
    10........................................................
    20........................................................
    99........................................................
    Pourquoi le fait d'ignorer la case est légèrement plus long? Le grep converti la lettre en majuscule/minuscule pour chaque ligne ?
    Idem avec un interval (dans ce ça, il y a une grande différence de perf) : le grep recalcule l'intervalle à chaque fois ?
    Pour le je comprend : il doit comparer plus de caractère dans chaque ligne donc c'est plus long.
    Par contre, je ne comprend pas pourquoi le grep inversé est si long.

  4. #4
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 835
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 835
    Billets dans le blog
    1
    Par défaut
    Salut

    Voici mes perfs avec Python pour ton fichier d'exemple recopié jusqu'à atteindre 32 636 323 lignes (chiffre totalement aléatoire, j'avais programmé une boucle et j'ai interrompu quand j'en ai eu marre)

    real 0m7.358s
    user 0m6.968s
    sys 0m0.388s

    Code Python
    Code python : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
     
    fp=open("fic", "r")
    for x in fp:
    	if len(x) == 12 and x[0] in "ABCDEF GHIJKLMNOPQRSTUVWXYZ": print x
    fp.close()

    L'avantage du Python par rapport au grep, c'est que tu peux affiner tes critères de recherche (tu auras aussi cette possibilité avec awk ou perl). Et son coté semi-compilé le rend quoi qu'il arrive 1000 fois plus rapide que le shell.
    Sinon pour tes questions oui c'est évident. Ne pas faire attention à la casse oblige grep à comparer avec la plage des majuscules puis celle des minuscules. Et mettre des intervalles l'oblige à les recalculer à chaque fois...

    PS: autre remarque à prendre en compte: l'affichage prend du temps. Moi j'ai eu ces perfs car j'ai lancé le script dans /dev/null. Si je l'avais laissé se dérouler à l'écran, bine évidemment que cela se serait compté en minutes. Et ceci est valable quels que soient tes outils de filtrage (grep, aw, perl, sed)...
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  5. #5
    Invité
    Invité(e)
    Par défaut
    Merci

    Comme je ne connais pas le Python ou le perl je vais rester sur le shell. Ce sera plus facile à comprendre pour ceux qui regarderons ce script dans le futur.
    Et puis, il ne s'agit qu'une petite partie du script final.

    Il est temps de mettre le sujet en "résolu"

  6. #6
    Expert confirmé Avatar de disedorgue
    Homme Profil pro
    Ingénieur intégration
    Inscrit en
    Décembre 2012
    Messages
    4 349
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur intégration
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Décembre 2012
    Messages : 4 349
    Par défaut
    Juste pour rajouter, que le 'lenght', que cela soit en awk, perl, python etc..., tient compte de la locale pour son calcul, pas du nombre d'octets.

    Sinon, vu les perf de python, je me demande ce que donnerait le langage 'julia' dans ce contexte...

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Grep? besoin de la colonne d'une seq recherchee
    Par Marionnet' dans le forum Linux
    Réponses: 6
    Dernier message: 17/08/2004, 18h14
  2. [ Eclipse 3 vs 2.1.2] Quelles sont les améliorations ?
    Par geegee dans le forum Eclipse Java
    Réponses: 5
    Dernier message: 26/05/2004, 16h55

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo