web-dev-qa-db-fra.com

Les modèles awk peuvent-ils correspondre à plusieurs lignes?

J'ai des fichiers journaux complexes dont j'ai besoin pour écrire des outils pour les traiter. J'ai joué avec awk mais je ne sais pas si awk est le bon outil pour cela.

Mes fichiers journaux sont des impressions de décodages de protocole OSPF qui contiennent un journal de texte des différents paquets de protocole et de leur contenu avec leurs différents champs de protocole identifiés avec leurs valeurs. Je veux traiter ces fichiers et imprimer uniquement certaines lignes du journal qui se rapportent à des paquets spécifiques. Chaque journal de paquet peut être composé d'un nombre variable de lignes pour l'entrée de ce paquet.

awk semble être en mesure de traiter une seule ligne qui correspond à un modèle. Je peux localiser le paquet souhaité, mais je dois ensuite faire correspondre les motifs dans les lignes qui suivent afin de déterminer s'il s'agit d'un paquet que je veux imprimer.

Une autre façon de voir les choses est que je voudrais isoler plusieurs lignes dans le fichier journal et imprimer ces lignes qui sont les détails d'un paquet particulier en fonction des correspondances de modèle sur plusieurs lignes.

Comme awk semble être basé sur des lignes, je ne sais pas si ce serait le meilleur outil à utiliser.

Si awk peut le faire, comment cela se fait-il? Sinon, avez-vous des suggestions sur l'outil à utiliser pour cela?

19
Andres Gonzalez

Awk peut facilement détecter des combinaisons de modèles sur plusieurs lignes, mais vous devez créer ce que l'on appelle un machine d'état dans votre code pour reconnaître la séquence.

Considérez cette entrée:

how
second half #1
now
first half
second half #2
brown
second half #3
cow

Comme vous l'avez vu, il est facile de reconnaître un seul motif. Maintenant, nous pouvons écrire un programme awk qui reconnaît la seconde moitié uniquement lorsqu'il est directement précédé d'une première moitié ligne. (Avec une machine d'état plus sophistiquée, vous pouvez détecter une séquence arbitraire de motifs.)

/second half/ {
  if(lastLine == "first half") {
    print
  }
}

{ lastLine = $0 }

Si vous exécutez cela, vous verrez:

second half #2

Maintenant, cet exemple est d'une simplicité absurde et ne représente à peine qu'une machine d'état. L'état intéressant ne dure que pendant la durée de l'instruction si et l'état précédent est implicite, selon la valeur de lastLine. Dans une machine à états plus canonique, vous conserveriez une variable d'état explicite et une transition d'état à état en fonction à la fois de l'état existant et de l'entrée actuelle. Mais vous n'aurez peut-être pas besoin d'autant de mécanisme de contrôle.

19
DigitalRoss

Awk est vraiment basé sur des enregistrements. Par défaut, il considère une ligne comme un enregistrement, mais vous pouvez le modifier avec la variable RS (séparateur d'enregistrement).

Une façon d'aborder cela serait de faire une première passe en utilisant sed (vous pouvez aussi le faire avec awk, si vous préférez), pour séparer les enregistrements avec un caractère différent comme un flux de formulaire. Ensuite, vous pouvez écrire votre script awk où il traitera le groupe de lignes comme un seul enregistrement.

Par exemple, s'il s'agit de vos données:

animal 0
name: joe
type: dog
animal 1
name: bill
type: cat
animal 2
name: ed
type: cat

Pour séparer les enregistrements avec des flux de formulaires:

$ cat data | sed $'s|^\(animal.*\)|\f\\1|'

Maintenant, nous allons prendre cela et le passer par awk. Voici un exemple d'impression conditionnelle d'un enregistrement:

$ cat data | sed $'s|^\(animal.*\)|\f\\1|' | awk '
      BEGIN { RS="\f" }                                     
      /type: cat/ { print }'

les sorties:

animal 1
name: bill
type: cat

animal 2
name: ed
type: cat

Edit: en bonus, voici comment le faire avec awk-ward Ruby (-014 signifie utiliser form-feed (code octal 014) comme séparateur d'enregistrement):

$ cat data | sed $'s|^\(animal.*\)|\f\\1|' |
      Ruby -014 -ne 'print if /type: cat/'
10
Vaz

awk est capable de traiter du modèle de début jusqu'au modèle de fin

/start-pattern/,/end-pattern/ {
  print
}

Je cherchais comment faire correspondre

 * Implements hook_entity_info_alter().
 */
function file_test_entity_type_alter(&$entity_types) {

ainsi créé

/\* Implements hook_/,/function / {
  print
}

dont le contenu dont j'avais besoin. Un exemple plus complexe consiste à sauter des lignes et à nettoyer les parties non spatiales. Remarque awk est un outil d'enregistrement (ligne) et Word (divisé par l'espace).

# start,end pattern match using comma
/ \* Implements hook_(.*?)\./,/function (.\S*?)/ {
  # skip PHP multi line comment end
  $0 ~ / \*\// skip

  # Only print 3rd Word
  if ($0 ~ /Implements/) {
    hook=$3
    # scrub of opening parenthesis and following.
    sub(/\(.*$/, "", hook)
    print hook
  }

  # Only print function name without parenthesis
  if ($0 ~ /function/) {
    name=$2

    # scrub of opening parenthesis and following.
    sub(/\(.*$/, "", name)

    print name
    print ""
  }
}

J'espère que cela aide aussi.

Voir aussi ftp://ftp.gnu.org/old-gnu/Manuals/gawk-3.0.3/html_chapter/gawk_toc.html

6
Clemens Tolboom

Je fais ce genre de chose avec les journaux sendmail, de temps en temps.

Donné:

Jan 15 22:34:39 mail sm-mta[36383]: r0B8xkuT048547: to=<www@web3>, delay=4+18:34:53, xdelay=00:00:00, mailer=esmtp, pri=21092363, relay=web3., dsn=4.0.0, stat=Deferred: Operation timed out with web3.
Jan 15 22:34:39 mail sm-mta[36383]: r0B8hpoV047895: to=<www@web3>, delay=4+18:49:22, xdelay=00:00:00, mailer=esmtp, pri=21092556, relay=web3., dsn=4.0.0, stat=Deferred: Operation timed out with web3.
Jan 15 22:34:51 mail sm-mta[36719]: r0G3Youh036719: from=<[email protected]>, size=0, class=0, nrcpts=0, proto=ESMTP, daemon=IPv4, relay=[50.71.152.178]
Jan 15 22:35:04 mail sm-mta[36722]: r0G3Z2SF036722: lost input channel from [190.107.98.82] to IPv4 after rcpt
Jan 15 22:35:04 mail sm-mta[36722]: r0G3Z2SF036722: from=<[email protected]>, size=0, class=0, nrcpts=0, proto=SMTP, daemon=IPv4, relay=[190.107.98.82]
Jan 15 22:35:36 mail sm-mta[36728]: r0G3ZXiX036728: lost input channel from ABTS-TN-dynamic-237.104.174.122.airtelbroadband.in [122.174.104.237] (may be forged) to IPv4 after rcpt
Jan 15 22:35:36 mail sm-mta[36728]: r0G3ZXiX036728: from=<[email protected]>, size=0, class=0, nrcpts=0, proto=SMTP, daemon=IPv4, relay=ABTS-TN-dynamic-237.104.174.122.airtelbroadband.in [122.174.104.237] (may be forged)

J'utilise un script quelque chose comme ça:

#!/usr/bin/awk -f

BEGIN {
  search=ARGV[1];  # Grab the first command line option
  delete ARGV[1];  # Delete it so it won't be considered a file
}

# First, store every line in an array keyed on the Queue ID.
# Obviously, this only works for smallish log segments, as it uses up memory.
{
  line[$6]=sprintf("%s\n%s", line[$6], $0);
}

# Next, keep a record of Queue IDs with substrings that match our search string.
index($0, search) {
  show[$6];
}

# Finally, once we've processed all input data, walk through our array of "found"
# Queue IDs, and print the corresponding records from the storage array.
END {
  for(qid in show) {
    print line[qid];
  }
}

pour obtenir la sortie suivante:

$ mqsearch airtel /var/log/maillog

Jan 15 22:35:36 mail sm-mta[36728]: r0G3ZXiX036728: lost input channel from ABTS-TN-dynamic-237.104.174.122.airtelbroadband.in [122.174.104.237] (may be forged) to IPv4 after rcpt
Jan 15 22:35:36 mail sm-mta[36728]: r0G3ZXiX036728: from=<[email protected]>, size=0, class=0, nrcpts=0, proto=SMTP, daemon=IPv4, relay=ABTS-TN-dynamic-237.104.174.122.airtelbroadband.in [122.174.104.237] (may be forged)

L'idée ici est que j'imprime toutes les lignes qui correspondent à l'ID de file d'attente Sendmail de la chaîne que je souhaite rechercher. La structure du code est bien sûr un produit de la structure du fichier journal, vous devrez donc personnaliser votre solution pour les données que vous essayez d'analyser et d'extraire.

2
ghoti
`pcregrep -M` works pretty well for this.

Depuis pcregrep (1):

-M, --multiline

Autorisez les motifs à correspondre à plusieurs lignes. Lorsque cette option est donnée, les modèles peuvent utilement contenir des caractères de nouvelle ligne littéraux et des occurrences internes de caractères ^ et $. La sortie d'une correspondance réussie peut être constituée de plusieurs lignes, la dernière étant celle sur laquelle la correspondance s'est terminée. Si la chaîne correspondante se termine par une séquence de nouvelle ligne, la sortie se termine à la fin de cette ligne.

Lorsque cette option est définie, la bibliothèque PCRE est appelée en mode "multiligne". Il existe une limite au nombre de lignes pouvant être mises en correspondance, imposée par la façon dont pcregrep met en mémoire tampon le fichier d'entrée lors de son analyse. Cependant, pcregrep garantit qu'au moins 8K caractères ou le reste du document (selon le plus court) sont disponibles pour la correspondance directe, et de même les 8K caractères précédents (ou tous les caractères précédents, si moins de 8K) sont garantis pour être disponibles pour les assertions de lookbehind. Cette option ne fonctionne pas lorsque l'entrée est lue ligne par ligne (voir --line-buffered.)

0
Cong Wang