2010-08-11 3 views
0

J'ai un script en Perl qui recherche une erreur qui se trouve dans un fichier de configuration, mais il imprime toute occurrence de l'erreur. Je dois faire correspondre ce qui se trouve dans le fichier de configuration et imprimer uniquement la dernière fois que l'erreur s'est produite. Des idées?Besoin d'imprimer la dernière occurrence d'une chaîne en Perl


Wow ... Je n'attendais pas autant de réponse. J'aurais dû être plus clair en disant que c'est pour la surveillance des journaux sur une boîte de Windows qui envoie une alerte à Nagios. C'est en fait mon premier programme Perl et toutes ces informations ont été très utiles. Est-ce que quelqu'un sait comment je peux appliquer ceci l'une des réponses de queue sur une boîte de wintel?

+3

Qu'avez-vous écrit jusqu'à présent? – msw

+0

manière la plus simple, utilisez la queue. par exemple. perl my_perl_script_that_prints_out_errors.pl | tail -1 – zen

Répondre

2

Dans les grandes lignes:

my $errinfo; 
while (<>) 
{ 
    $errinfo = "whatever" if (m/the error pattern/); 
} 
print "error: $errinfo\n" if ($errinfo); 

Ce attrape toutes les erreurs, mais n'imprime pas jusqu'à la fin, lorsque seul le dernier survit.

4

Une autre façon de le faire:

perl -n -e '$e = $1 if /(REGEX_HERE)/; END{ print $e }' CONFIG_FILE_HERE 
+0

Juste un petit commentaire: pour stocker la ligne entière, utilisez '$ _' au lieu de' $ 1', ou utilisez '$ .' pour stocker le numéro de ligne où le motif a été trouvé. Bonne réponse, utilisez cette approche moi-même plusieurs fois –

4

Que voulez-vous besoin d'imprimer? La ligne contenant l'erreur? Plus de contexte que ça? File::ReadBackwards peut être utile.

0

Une approche en force brute implique la configuration de votre propre pipeline en pointant STDOUT à tail. Cela vous permet d'imprimer toutes les erreurs, puis c'est à tail de se soucier de ne laisser que le dernier.

Vous n'avez pas spécifié, je suppose donc une ligne de configuration juridique est de la forme

Name = some value 

Matching qui est simple:

  • ^ (à partir du début de la ligne)
  • \w+ (un ou plusieurs «caractères de mot»)
  • \s+ (suivi d'un espace obligatoire)
  • = (suivi d'un signe égal)
  • \s+ (plus les espaces obligatoires)
  • .+ (une valeur obligatoire)
  • $ (finition à la fin de la ligne)

collant ensemble, nous obtenons

#! /usr/bin/perl 

use warnings; 
use strict; 

# for demo only 
*ARGV = *DATA; 

my $pid = open STDOUT, "|-", "tail", "-1" or die "$0: open: $!"; 
while (<>) { 
    print unless /^ \w+ \s+ = \s+ .+ $/x; 
} 

close STDOUT or warn "$0: close: $!"; 

__DATA__ 
This = assignment is ok 
But := not this 
And == definitely not this 

Sortie:

$ ./lasterr 
And == definitely not this

Avec des expressions régulières, quand vous voulez la dernière occurrence d'un motif, placez ^.* à l'avant de votre modèle.Par exemple, pour remplacer le dernier X dans l'entrée avec Y, utilisez

$ echo XABCXXXQQQXX | perl -pe 's/^(.*)X/$1Y/' 
XABCXXXQQQXY

Notez que le ^ est redondant, car regular-expression quantifiers sont avides, mais j'aime l'avoir là pour l'accent.

En appliquant cette technique à votre problème, vous pouvez rechercher la dernière ligne dans votre fichier de configuration qui contient une erreur dans le programme suivant:

#! /usr/bin/perl 

use warnings; 
use strict; 

local $_ = do { local $/; scalar <DATA> }; 
if (/\A.* ^(?! \w+ \s+ = \s+ [^\r\n]+ $) (.+?)$/smx) { 
    print $1, "\n"; 
} 

__DATA__ 
This = assignment is ok 
But := not this 
And == definitely not this 

La syntaxe de l'expression régulière est un peu différent car $_ contient plusieurs lignes, mais le principe est le même. \A est similaire à ^, mais il correspond à seulement au début de la chaîne à rechercher. Avec les /m switch (“multi-line”), ^ correspond aux limites de ligne logique.

Jusqu'à ce point, nous savons que le modèle

/\A.*^.../ 

correspond à la dernière ligne qui ressemble à quelque chose. Le negative look-ahead assertion(?!...) recherche une ligne qui est pas une ligne de configuration légale. En règle générale, . correspond à n'importe quel caractère sauf le saut de ligne, mais le /s switch (“single line”) lève cette restriction. La spécification de [^\r\n]+, c'est-à-dire un ou plusieurs caractères qui ne sont ni retour chariot, ni saut de ligne, ne permet pas à la correspondance de déborder dans la ligne suivante.

Look-around assertions ne pas capturer, donc nous attrapons la ligne fautive avec (.+?)$. La raison pour laquelle il est sûr d'utiliser . dans ce contexte est que nous savons que la ligne en cours est mauvaise et que non-greedy quantifier +? cesse de correspondre dès que possible, ce qui dans ce cas est la fin de la ligne logique actuelle.

Toutes ces expressions régulières utilisent le /x switch (“extended mode”) pour autoriser des espaces supplémentaires: l'objectif est d'améliorer la lisibilité.

Questions connexes