2009-05-18 6 views
1

Je tente de "grep" out bind pour un utilisateur spécifique à partir d'un fichier journal LDAP. Les lignes dont j'ai besoin seront réparties sur plusieurs lignes dans le journal. Voici entrée exemple:sed: utilisation de variables sur plusieurs lignes

[2009/04/28 17:04:42.414] DoBind on connection 0x7c8affc0 
[2009/04/28 17:04:42.414] Bind name:cn=admin,ou=appids,o=admineq, version:3, authentication:simple 
[2009/04/28 17:04:42.415] Failed to authenticate local on connection 0x6cc8ee80, err = log account expired (-220) 
[2009/04/28 17:04:42.416] Sending operation result 53:"":"NDS error: log account expired (-220)" to connection 0x6cc8ee80 
[2009/04/28 17:04:42.416] Operation 0x3:0x60 on connection 0x6cc8ee80 completed in 3 seconds 
[2009/04/28 17:04:42.416] Sending operation result 0:"":"" to connection 0x7c8affc0 
[2009/04/28 17:04:42.416] Operation 0x1:0x60 on connection 0x7c8affc0 completed in 0 seconds 
[2009/04/28 17:04:48.772] DoSearch on connection 0x7c8affc0 
[2009/04/28 17:04:48.772] Search request: 
base: "o=intranet" 
scope:2 dereference:0 sizelimit:0 timelimit:600 attrsonly:0 
filter: "(guid='03ADmin)" 
attribute: "cn" 
attribute: "cn" 
attribute: "cn" 
attribute: "cn" 
attribute: "objectClass" 
attribute: "guid" 
attribute: "mail" 
[2009/04/28 17:04:48.773] Sending operation result 0:"":"" to connection 0x7c8affc0 
[2009/04/28 17:04:48.773] Operation 0xe851:0x63 on connection 0x7c8affc0 completed in 0 seconds 

Pour cet exemple, ce qui suit devrait être le résultat:

[2009/04/28 17:04:42.414] DoBind on connection 0x7c8affc0 
[2009/04/28 17:04:42.414] Bind name:cn=admin,ou=appids,o=admineq, version:3, authentication:simple 
[2009/04/28 17:04:42.416] Sending operation result 0:"":"" to connection 0x7c8affc0 
[2009/04/28 17:04:42.416] Operation 0x1:0x60 on connection 0x7c8affc0 completed in 0 seconds 

Fondamentalement, c'est un journal des opérations de serveur à travers plusieurs connexions. J'ai besoin d'analyser le temps passé dans les opérations 'bind' par l'utilisateur admin, mais ce serveur est très occupé, donc j'ai besoin d'éliminer beaucoup de bruit.

En pseudocode:

for each line in file 
    if line contains "DoBind" and next line contains "cn=admin" 
     print both lines 
     find the connection number X in lines 
     skip lines until "Sending operation result.*to connection X" is found 
     print two lines 

Je voudrais obtenir les « doBind » lignes qui sont précédées par l'utilisateur « cn = admin » et les lignes de résultat, qui sont classées en fonction du numéro de connexion " 0x7c8affc0 "dans cet exemple. D'autres opérations peuvent avoir lieu entre le début et la fin de la liaison dont je n'ai pas besoin, comme le message "Impossible d'authentifier", qui se déroule sur une connexion différente.

En outre, d'autres opérations auront lieu sur la connexion après que la liaison est faite ce qui ne m'intéresse pas. Dans ce qui précède, les résultats de l'opération DoSearch après le 'bind' ne doivent pas être capturés. J'essaye de faire ceci avec 'sed', qui a semblé être le bon outil pour le travail. Hélas, je suis un débutant et c'est une expérience d'apprentissage. Voici ce que j'ai jusqu'à présent:

/.*DoBind on connection \(0x[0-9a-f]*\)\n.*Bind name:cn=OblixAppId.*/ p 
/.*Sending operation result.*to connection \1\nOperation.*on connection \1 completed.*/ p 

sed se plaint de la deuxième ligne où j'utilise '\ 1'. J'essaie de capturer l'adresse de connexion et de l'utiliser dans une recherche ultérieure pour capturer les chaînes de résultats, mais je ne l'utilise évidemment pas correctement. Les variables '#' semblent être locales à chaque opération de recherche.

Existe-t-il un moyen de passer des "variables" d'une recherche à une autre ou devrais-je plutôt apprendre perl?

Répondre

0

Eh bien, je ne pouvais pas trouver une solution avec sed seul. Voici ma solution perl laid:

open INFILE, $ARGV[0] or die "Couldn't open file $ARGV[0]"; 
while (<INFILE>) { 
    if (/(.*DoBind on connection (0x[0-9a-f]*))/) { 
    $potentialmatch = $1; $connid = $2; 
    $currentline = <INFILE>; 
    if ($currentline =~ /(.*Bind name:cn=OblixAppId.*)/) { 
     print $potentialmatch . "\n" . $1 . "\n"; 
     $offset = tell INFILE; 
     while($currentline = <INFILE>) { 
     if ($currentline =~ /(.*Sending operation result.*to connection $connid.*)/) { 
      print "$1\n"; 
      next; 
     } 
     if ($currentline =~ /(.*Operation.*on connection $connid completed.*)/) { 
      print "$1\n"; 
      seek INFILE, $offset, 0; 
      last; 
     } 
     } 
    } 
    } 
} 
1
fgrep -B1 cn=admin logfile | 
sed -n 's/.*DoBind on connection \(.*\)/\1/p' | 
fgrep -wf - logfile 

Ce premier fgrep extrait de la ligne de liaison et de la ligne précédente (-B1), le sed tire sur le numéro de connexion et la fgrep finale trouve toutes les lignes qui contiennent l'un des numéros de connexion.

Il s'agit d'une solution à deux passes, une passe est possible mais plus compliquée à mettre en œuvre.

Editer: Voici une solution qui fait ce que vous voulez en python. Notez cependant que ceci n'est pas entièrement correct, car il ne gérera pas correctement les lignes de journaux entrelacées entre différentes connexions - je vous laisserai le soin de le faire si vous en tenez suffisamment compte. C'est aussi un peu inefficace, et fait plus de regex compile et correspond que nécessaire.

import re 

todo = set() 
display_next = False 
previous_dobind = None 

for line in open('logfile'): 
    line = line.strip() 
    if display_next: 
    print line 
    display_next = False 
    continue 
    dobind = re.search('DoBind on connection (.*)', line) 
    bind = re.search('Bind name:cn=admin', line) 
    oper = re.search('Sending operation result.*to connection (.*)', line) 
    if dobind: 
    previous_dobind = (dobind.groups(1), line) 
    elif previous_dobind: 
    if bind: 
     todo.add(previous_dobind[0]) 
     print previous_dobind[1] 
     print line 
    previous_dobind = None 
    elif oper: 
    conn = oper.groups(1) 
    if conn in todo: 
     print line 
     display_next = True 
     todo.remove(conn) 
+0

Merci, mais il y aura d'autres opérations qui ont lieu sur ces liens que je ne suis pas intéressé. Les lignes de résultats ne permettent pas d'identifier le fait que le résultat était une « opération de liaison » . La deuxième partie de ce script finirait par me donner tous les résultats d'opération qui se sont produits sur toute connexion à laquelle l'administrateur s'est lié. Je vais ajouter ceci à la question. – veefu

+0

Ce n'est pas tout à fait clair pour moi ce que vous voulez. Quelles lignes voulez-vous en sortie? Pouvez-vous fournir un exemple de sortie? Basé sur votre description "fgrep -v DoSearch" ou un "egrep (complété | Envoyé)" à la fin de ma solution ci-dessus ferait. –

+0

ce qui m'inquiète à propos de cette solution est "le fgrep final trouve toutes les lignes qui contiennent l'un des numéros de connexion" Je ne veux pas toutes les lignes qui contiennent les numéros de connexion, je veux seulement les premières lignes trouvées pour une connexion DoBind "a été effectué sur la connexion J'ai ajouté des exemples de résultats – veefu

1

Vous allez vouloir regarder de près une référence sed si vous le voulez en un seul passage - vous pouvez certainement le faire. Regardez dans les commandes sed qui permutent les tampons hold et pattern, et comparez les deux. Vous pouvez écrire une règle à plusieurs étapes qui correspond à "cn = admin", et l'échanger avec le tampon de maintien, puis faire correspondre le modèle "DoBind" lorsque le tampon de maintien n'est pas vide. Je ne me souviens plus des commandes, mais ce n'est pas très compliqué; vous aurez juste besoin de le chercher dans la documentation de référence.

+0

Merci d'avance, je suis en train de lire dessus, mais je ne sais pas comment ça s'applique. = "ligne d'admin" n'est pas le point de trouble Le problème est de passer l'adresse de connexion, qui change, au modèle de recherche suivant Voulez-vous dire que je vais extraire le champ d'adresse d'une ligne correspondante et l'ajouter à la suivante tampon de motif? – veefu

+0

ah, désolé. J'ai mal lu un peu. Oui, vous pouvez extraire un champ d'une ligne correspondante et le coller dans le tampon de maintien. Ensuite, votre autre règle essayera de faire correspondre sur le modèle DoBind, mais seulement si le tampon de maintien n'est pas vide. –

+0

Je me considère assez versé dans les scripts sed et shell, et c'est le genre de choses que je dois toujours consulter dans le manuel de référence.Le traitement multi-lignes avec un outil basé sur une ligne est juste une astuce intrinsèque, même si c'est probablement le meilleur outil pour le travail à court d'un programme à part entière écrit dans un langage généraliste. Si vous n'arrivez pas à faire fonctionner ceci dans un script sed, vous pourriez revenir à bash, car il a des opérateurs regex intégrés (ou perl-shudder - si vous êtes plus à l'aise avec ça). –

2

En tant que défi intellectuel, je suis venu avec une solution en utilisant sed (comme l'avait demandé), mais je dirais que l'utilisation d'une autre technologie (perl dans mon préféré) serait plus facile à comprendre, et donc plus facile à soutenir.

Vous avez deux options où est vient à un traitement multi-ligne sed:

  • vous pouvez utiliser le attente espace - qui peut être utilisé pour stocker tout ou partie de l'espace de travail pour le traitement ultérieur, ou
  • vous pouvez ajouter d'autres lignes à l'espace modèle en utilisant des commandes telles que N.

    vous pouvez utiliser l'espace de maintien

Note: l'exemple ci-dessous utilise GNU sed. Il peut en outre être fait pour fonctionner avec Solaris sed en changeant la syntaxe multi-commande (';' remplacé par). J'ai utilisé la variante GNU sed pour rendre le script plus compact.

Le script ci-dessous est commenté, pour le bénéfice du lecteur et mine.

sed -n ' 
# if we see the line "DoBind" then store the pattern in the hold space 
/DoBind/ h 

# if we see the line "cn=admin", append the pattern to the holdspace 
# and branch to dobind 
/cn=admin/{H;b dobind} 

# if we see the pattern "Sending...." append the hold space to the 
# pattern and branch to doop 
/Sending operation result/{G;b doop} 

# branch to the end of the script 
b 

# we have just seen a cn=admin, ad the hold space contains the last 
# two lines 
:dobind 

# swap hold space with pattern space 
x 

# print out the pattern space 
p 

# strip off everying that is not the connection identifier 
s/^.*connection // 
s/\n.*$// 

# put it in the hold space 
x 

# branch to end of script. 
b 

# have just seen "Sending operation" and the current stored connection 
#identifier has been appended to the pattern space 
:doop 

# does the connection id on both lines match? Yes do to gotop. 
/connection \(0x[0-9a-f]*\).*\n\1$/ b gotop 

# branch to end of script 
b 

# pattern contains two lines "Sending....", and the connection id. 
:gotop 

# delete the second line 
s/\n.*$// 

# read the next line and append it to the pattern space. 
N 

# print it out 
p 

# clear the pattern space, and put it into the hold space - hence 
# clearing the hold space 
s/^.*$// 
x 

'

Questions connexes