#1 Le 29/09/2009, à 11:03
- BorX
[Résolu] Shell : Optimisation : grep vs double-grep vs sed
Bonjour,
Je fais une repasse sur un Shell où il est question de parcourir un fichier de log pour compter le nombre de connexions et déconnexions à la date en cours.
Un premier grep consiste donc à sélectionner toutes les lignes comprenant le mot "Connexion" ou "Déconnexion".
De ce résultat, on ne garde que les lignes concernant la date en cours avec un second grep.
De ce résultat, on ne garde que le mot "Connexion" ou "Déconnexion" à l'aide de cut.
Et enfin, on trie et compte le nombre de mots avec sort et uniq.
$ time grep -E '(C|Déc)onnexion' fichier.log | grep $(date +%Y-%m-%d) | cut -d ' ' -f10 | sort | uniq -c
2390 Connexion
1938 Déconnexion
real 0m0,59s
user 0m0,48s
sys 0m0,02s
Ça marche, mais je trouvais que ça faisait beaucoup de commandes, et qu'il était possible d'optimiser tout ça...
J'ai donc cherché, dans un premier temps, à réunir les 2 grep :
$ time grep -E "$(date +%Y-%m-%d).*(C|Déc)onnexion" fichier.log | cut -d ' ' -f10 | sort | uniq -c
2390 Connexion
1938 Déconnexion
real 0m4,03s
user 0m3,02s
sys 0m0,03s
Surprise ! Son exécution est 4 fois plus lente !
Je me dis alors qu'un sed serait peut-être plus adapté (un seul sed remplace à lui tout seul les 2 grep et le cut) :
$ time sed -n "s/^.*$(date +%Y-%m-%d).* \(.*onnexion\).*$/\1/p" fichier.log | sort | uniq -c
2390 Connexion
1938 Déconnexion
real 0m7,65s
user 0m5,70s
sys 0m0,06s
Nouvelle surprise ! C'est encore pire !
Moralité, il vaut mieux utiliser 2 grep et un cut, plutôt qu'un sed ??
J'ai toujours cru qu'il valait mieux limiter le nombre d'enchaînements de processus, et qu'il fallait privilégier les awk/sed aux grep/tail/cut/...
Sauriez-vous m'expliquer pourquoi la première commande est finalement plus optimisée ?
Serait-ce mon sed que je n'ai pas bien agencé ??
Merci pour vos lumières...
Dernière modification par BorX (Le 29/09/2009, à 16:25)
Hors ligne
#2 Le 29/09/2009, à 11:29
- Peck
Re : [Résolu] Shell : Optimisation : grep vs double-grep vs sed
Ton problème vient de l'utilisation de regex ainsi que de l'utilisation de .*
Hors ligne
#3 Le 29/09/2009, à 11:37
- Coolgeek
Re : [Résolu] Shell : Optimisation : grep vs double-grep vs sed
Dans ta 1ere ligne de commande, je vois que tu les trie, y'a une raison particulière ?
Hors ligne
#4 Le 29/09/2009, à 12:07
- BorX
Re : [Résolu] Shell : Optimisation : grep vs double-grep vs sed
Merci pour vos réponses rapides.
Dans ta 1ere ligne de commande, je vois que tu les trie, y'a une raison particulière ?
Oui : il convient d'utiliser sort avant d'utiliser uniq.
Ton problème vient de l'utilisation de regex ainsi que de l'utilisation de .*
Intéressant.
J'utilise pourtant des regex dès la première commande : grep -E '(C|Déc)onnexion'
mais effectivement sans .*
Je comprends que l'utilisation de .* alourdisse la regex, mais comment s'en passer ?
Hors ligne
#5 Le 29/09/2009, à 12:11
- BorX
Re : [Résolu] Shell : Optimisation : grep vs double-grep vs sed
Je comprends que l'utilisation de .* alourdisse la regex, mais comment s'en passer ?
Peut-être que la réponse se trouve dans la question
On s'en passe en séparant les recherches... D'où les 2 grep. C'est ça ?
Hors ligne
#6 Le 29/09/2009, à 15:58
- Peck
Re : [Résolu] Shell : Optimisation : grep vs double-grep vs sed
Tu peux peut-etre améliorer les choses avec perl et des regex utilisant .*?
D'autre part dans ta première ligne tu faisais uniquement rechercher suivi d'un cut, tu fais ensuite rechercher et remplacer ce qui implique des regex plus compliquées.
Enfin si tu utilise perl, tu peux passer l'intégralité de ta ligne en une seul ligne perl.
Hors ligne
#7 Le 29/09/2009, à 16:25
- BorX
Re : [Résolu] Shell : Optimisation : grep vs double-grep vs sed
Merci pour ces conseils.
Je comprends le principe de lourdeur en utilisant .* (il parcourt chaque ligne caractère par caractère pour voir si la suite de la regex match).
Bref, j'étais resté dubitatif en constatant les perfs lamentable de ma commande sed, mais vous m'avez fourni l'explication, donc c'est parfait
Donc, je vais rester avec mes double-grep/cut et puis voilà !
Et je vais revoir certains sed que j'emploie un peu trop avec des .* dans tous les sens.
A ce sujet, je patine : impossible de trouver le moyen de faire l'équivalent du grep -o. Mais ça fera l'objet d'un autre topic.
Merci à tous !
Hors ligne
#8 Le 29/09/2009, à 22:23
- AnsuzPeorth
Re : [Résolu] Shell : Optimisation : grep vs double-grep vs sed
Bjr,
Avec sed, l'équivalent de "grep -o" , je pense,
sed -n '/item/p' fichier.txt
Interface graphique pour bash, python ou autre: glade2script
Support Tchat: http://chat.jabberfr.org/muckl_int/inde … ade2script (Hors ligne)
Hors ligne
#9 Le 30/09/2009, à 09:43
- BorX
Re : [Résolu] Shell : Optimisation : grep vs double-grep vs sed
Merci pour l'idée.
L'inconvénient, c'est que l'action 'p' de sed renvoie toute la ligne, et pas seulement ce qu'on recherche.
Grosso modo, je voudrais faire ça, mais sans les .* :
sed -n 's/^.*\(regex\).*$/\1/p' fichier.txt
Ce qu'on fait simplement avec un grep -Eo :
grep -Eo "regex" fichier.txt
Hélas, développant sous AIX, je ne dispose pas d'une version de grep suffisamment avancée.
Effectivement, une solution perl serait un bonne alternative, mais je me demandais si sed possédait une autre action que 'p' consistant à n'afficher que ce qui est demandé, et pas toute la ligne.
Dernière modification par BorX (Le 30/09/2009, à 09:44)
Hors ligne
#10 Le 30/09/2009, à 17:05
- Totor
Re : [Résolu] Shell : Optimisation : grep vs double-grep vs sed
Bonjour,
Pourquoi la version sed ne te convient pas ?
j'ai un AIX sous la main (jusqu'à ce soir...après je sais pô) et ceci fonctionne :
awk ' {outLine="";while (match($0,/toto/) > 0) {outLine=outLine " " substr($0,RSTART,RLENGTH);sub(/toto/,"")}; print outLine}' <<< "toto totoa iti toto"
change /toto/ par ton ERE...
-- Lucid Lynx --
Hors ligne
#11 Le 30/09/2009, à 17:12
- BorX
Re : [Résolu] Shell : Optimisation : grep vs double-grep vs sed
Cette nuit, j'ai rêvé que Totor me répondait... et Totor l'a fait !
La version sed me convient en théorie, mais les performances sont désastreuses, vraisemblablement à cause de l'utilisation abusive de .*
Aussi, je cherchais un moyen de faire du sed (généralement préférable à l'accumulation de grep) de façon un peu plus optimisé.
Tu réponds (peut-être) à ma question, par une commande qui me dépasse pour le moment.
Merci. Je vais comparer les perfs de chacune des commandes pour faire mon choix entre le plus rapide et le plus élégant.
Hors ligne
#12 Le 30/09/2009, à 18:17
- BorX
Re : [Résolu] Shell : Optimisation : grep vs double-grep vs sed
Ingénieux, finalement assez simple quand on se penche dessus (le substr($0,RSTART,RLENGTH) m'échappe encore un peu)... et efficace (a priori aussi rapide qu'un grep) !
Après adaptation, je vais certainement l'adopter
Merci !
Dernière modification par BorX (Le 30/09/2009, à 18:17)
Hors ligne
#13 Le 30/09/2009, à 18:43
- BorX
Re : [Résolu] Shell : Optimisation : grep vs double-grep vs sed
Mon script awk n'est certainement pas optimisé et pourtant on sent déjà une différence :
$ time awk '{
cpt=1
while (cpt <= 2 && match($0, /Current thread busy: ([0-9]*)/) > 0) {
if (cpt < 2) sub(/Current thread busy: ([0-9]*)/, "")
else print substr($0, RSTART + 21, RLENGTH - 21)
cpt++
}
}' status.txt
2
real 0m0.028s
user 0m0.030s
sys 0m0.015s
$ time sed -n 's/^.*Current thread busy: \([0-9]*\).*$/\1/p' status.txt
2
real 0m0.040s
user 0m0.046s
sys 0m0.046s
Dernière modification par BorX (Le 30/09/2009, à 18:44)
Hors ligne
#14 Le 30/09/2009, à 20:21
- Totor
Re : [Résolu] Shell : Optimisation : grep vs double-grep vs sed
[...]le substr($0,RSTART,RLENGTH) m'échappe encore un peu[..]
Cela permet d'extraire de $0 le motif détecté par match
En effet, match retourne l'indice de l'expression recherchée dans la chaine demandée mais valorise aussi la variable RSTART par cet indice et RLENGTH avec la longueur de la chaine trouvée correspondant au motif recherché.
-- Lucid Lynx --
Hors ligne
#15 Le 01/10/2009, à 10:11
- BorX
Re : [Résolu] Shell : Optimisation : grep vs double-grep vs sed
awk is my new religion ; Totor is my prophet.
Hors ligne