Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

Extraire certaines lignes d'un fichier log

18 réponses
Avatar
Gauthier
Bonjour à tous,

Si un fichier log comprend à certains intervalles une ligne
avec un motif caractéristique, comme par exemple

-- MARK --

comme on peut trouver dans certains /var/log/messages,
ou tout autre repère temporel qu'on insèrerait avec cron + logger,
comment, avec des outils de base comme sed, awk, grep...
afficher ce qui figure entre la dernière ligne de ce type et la fin du
fichier ?

Encore mieux, comment afficher les n dernières "tranches" de ce log
délimitées par ces lignes ?

Merci d'avance,
--
^^ Gauthier
(_____/°°-ç
| \_`-"
)/@mmm||
\nn \nn FOE-Belgium : http://www.amisdelaterre.be

10 réponses

1 2
Avatar
Jean-Louis Liagre
Gauthier wrote:
Bonjour à tous,

Si un fichier log comprend à certains intervalles une ligne
avec un motif caractéristique, comme par exemple

-- MARK --

comme on peut trouver dans certains /var/log/messages,
ou tout autre repère temporel qu'on insèrerait avec cron + logger,
comment, avec des outils de base comme sed, awk, grep...
afficher ce qui figure entre la dernière ligne de ce type et la fin du
fichier ?


LOGFILE=/var/log/messages
sed -n "$(grep -n MARK $LOGFILE|tail -1| nawk -F : '{print $1}'),$p"
$LOGFILE

Avatar
Stephane Chazelas
On 22 Aug 2005 19:21:47 GMT, Gauthier wrote:
[...]
Si un fichier log comprend à certains intervalles une ligne
avec un motif caractéristique, comme par exemple

-- MARK --

comme on peut trouver dans certains /var/log/messages,
ou tout autre repère temporel qu'on insèrerait avec cron + logger,
comment, avec des outils de base comme sed, awk, grep...
afficher ce qui figure entre la dernière ligne de ce type et la fin du
fichier ?


Avec GNU tac (certains systemes ont "tail -r" qui fait
l'equivalent)

tac < file | sed '/-- MARK --/q' | tac

Sinon,

awk '/-- MARK --/ {n=0}
{l[n++] = $0}
END { for (i=0; i<n; i++) print l[i]}' < file

mais ca veut dire lire le fichier en entier.

Encore mieux, comment afficher les n dernières "tranches" de ce log
délimitées par ces lignes ?


tac < file | awk -v n=5 '/-- MARK --/ && (--n == 0) {exit}' | tac

Sur les systemes sans tac, mieux vaut passer par perl et faire
un peu de programmation avec des lseek. A moins qu'ont puisse
vivre avec lire le fichier deux fois en entier pour d'abord
reperer les lignes a extraire, puis les extraire.

--
Stephane

Avatar
Stephane Chazelas
On Mon, 22 Aug 2005 22:30:42 +0200, Jean-Louis Liagre wrote:
[...]
LOGFILE=/var/log/messages
sed -n "$(grep -n MARK $LOGFILE|tail -1| nawk -F : '{print $1}'),$p"
$LOGFILE


grep est un sous ensemble de awk, on n'a en general pas besoin
de les piper ensemble. $(...) n'est pas Bourne mais est POSIX.
nawk n'est pas une commande POSIX, et il n'y rien dans cette
commande awk qui ne marcherait pas meme avec le awk originel
$LOGFILE n'est pas correct sans ses quotes et sans "--" avant.
S'il n'y a pas de "MARK", tu auras une syntax error de sed.
Tout sur une ligne, c'est pas tres lisisble.

last_mark_line_number=$(
awk '
/MARK/ {
n = NR
}
END {
if (n == 0) n = 1
print n
}' < "$LOGFILE"
)
sed -n "$last_mark_line_number,$p" < "$LOGFILE"

Note que ca signifie lire le fichier en entier deux fois (tac |
sed | tac dans mon exemple ne lit que la fin du fichier une
fois mais n'est pas portable).

--
Stephane

Avatar
Laurent Wacrenier
Stephane Chazelas écrit:
Note que ca signifie lire le fichier en entier deux fois (tac |
sed | tac dans mon exemple ne lit que la fin du fichier une
fois mais n'est pas portable).


Il le lit qu'une fois, mais il le met deux fois en mémoire...

Avatar
Jean-Louis Liagre
Stephane Chazelas wrote:
On Mon, 22 Aug 2005 22:30:42 +0200, Jean-Louis Liagre wrote:
[...]

LOGFILE=/var/log/messages
sed -n "$(grep -n MARK $LOGFILE|tail -1| nawk -F : '{print $1}'),$p"
$LOGFILE



grep est un sous ensemble de awk, on n'a en general pas besoin
de les piper ensemble.


C'est mon choix.

$(...) n'est pas Bourne mais est POSIX.


Ben oui, c'est pas bien ?

nawk n'est pas une commande POSIX, et il n'y rien dans cette
commande awk qui ne marcherait pas meme avec le awk originel


Plus précisément, nawk est le awk POSIX sous Solaris
(/usr/xpg4/bin/awk), et surtout, il va beaucoup plus vite.

$LOGFILE n'est pas correct sans ses quotes et sans "--" avant.


Pas quand logfile vaut /var/adm/messages.

S'il n'y a pas de "MARK", tu auras une syntax error de sed.


Bien vu.

2ème essai:

#!/bin/ksh
LOGFILE="/var/log/messages"
sed -n "$(grep -n MARK -- "$LOGFILE"||echo 1|tail -1|
awk -F : '{print $1}'),$p" -- "$LOGFILE"

Tout sur une ligne, c'est pas tres lisisble.


Mais beaucoup plus rigolo.

last_mark_line_number=$(
awk '
/MARK/ {
n = NR
}
END {
if (n == 0) n = 1
print n
}' < "$LOGFILE"
)
sed -n "$last_mark_line_number,$p" < "$LOGFILE"


Note que ca signifie lire le fichier en entier deux fois (tac |
sed | tac dans mon exemple ne lit que la fin du fichier une
fois mais n'est pas portable).


La deuxième fois, le fichier est dans le cache, si le système
n'est pas a court de RAM, c'est pas mortel.

Bien sûr, si le fichier de logs fait un ou deux gigas, tac
devient très intéressant ...


Avatar
David LE BOURGEOIS

Avec GNU tac (certains systemes ont "tail -r" qui fait
l'equivalent)

tac < file | sed '/-- MARK --/q' | tac


Sur les systèmes où les outils GNU ne sont pas présents, j'ai l'habitude
d'utiliser sed pour remplacer tac :

sed '1!G;h;$!d'

Si l'on remplace chaque appel à tac par un appel à sed, on obtient 3 sed
enchaînés par tubes :

sed '1!G;h;$!d' | sed '/--MARK--/q' | sed '1!G;h;$!d'

N'y aurait-il pas un moyen de factoriser tout ça, en un seul appel à
sed ?

--
David LE BOURGEOIS

Avatar
Stephane Chazelas
On Tue, 23 Aug 2005 16:06:49 +0200, Jean-Louis Liagre wrote:
[...]
$(...) n'est pas Bourne mais est POSIX.


Ben oui, c'est pas bien ?


Si, mais c'est a noter. Ca ne marchera pas avec le /bin/sh de
Solaris par exemple.

nawk n'est pas une commande POSIX, et il n'y rien dans cette
commande awk qui ne marcherait pas meme avec le awk originel


Plus précisément, nawk est le awk POSIX sous Solaris
(/usr/xpg4/bin/awk), et surtout, il va beaucoup plus vite.


Non, sous Solaris, nawk est different de /usr/xpg4/bin/awk meme
si /usr/xpg4/bin/awk est plus proche de nawk que de
/usr/bin/awk. nawk n'est pas POSIX conformant (du moins, moins
que /usr/xpg4/bin/awk) et la commande n'existe pas forcement sur
tous les Unix vu qu'elle n'est pas standardisee.


$LOGFILE n'est pas correct sans ses quotes et sans "--" avant.


Pas quand logfile vaut /var/adm/messages.


Ca depend de la valeur d'IFS. Mais c'est une question de syntaxe
pour moi, pas de "cas particulier".

S'il n'y a pas de "MARK", tu auras une syntax error de sed.


Bien vu.

2ème essai:

#!/bin/ksh
LOGFILE="/var/log/messages"
sed -n "$(grep -n MARK -- "$LOGFILE"||echo 1|tail -1|
awk -F : '{print $1}'),$p" -- "$LOGFILE"



LOGFILE="/var/log/messages"
sed -n "$({ grep -n MARK -- "$LOGFILE"||echo 1;} |tail -1|
awk -F : '{print $1}'),$p" < "$LOGFILE"

Sinon, le tail ne s'applique qu'a echo.

Et ni /usr/xpg4/bin/awk ni nawk ne supportent "--" sous Solaris.
De plus, probleme si les noms de fichiers contiennent des "=",
mieux vaut laisser le shell ouvrir le fichier (l'alternative est
de remplacer les fichiers "fooºr" par "./fooºr").

Qui a dit que le shell etait mieux que perl?

--
Stephane


Avatar
Stephane Chazelas
On 23 Aug 2005 16:04:43 GMT, David LE BOURGEOIS wrote:

Avec GNU tac (certains systemes ont "tail -r" qui fait
l'equivalent)

tac < file | sed '/-- MARK --/q' | tac


Sur les systèmes où les outils GNU ne sont pas présents, j'ai l'habitude
d'utiliser sed pour remplacer tac :

sed '1!G;h;$!d'


Tu as besoin du GNU sed pour ca ;). Car tout le fichier se
retrouve en memoire et il n'y a guere que le GNU sed pour
oublier de mettre une limitation ici.

Si l'on remplace chaque appel à tac par un appel à sed, on obtient 3 sed
enchaînés par tubes :

sed '1!G;h;$!d' | sed '/--MARK--/q' | sed '1!G;h;$!d'

N'y aurait-il pas un moyen de factoriser tout ça, en un seul appel à
sed ?


Si, une fois que tu as tout le fichier en memoire, tu peux faire
un s/././

sed '1!G;h;$!d;s/.*(--MARK--)/1/'

Mais encore une fois, ca met tout le fichier en memoire et ne
marchera pas avec tous les sed, a moins que le fichier soit
tres petit.

--
Stephane


Avatar
drkm
Laurent Wacrenier writes:

Il le lit qu'une fois, mais il le met deux fois en mémoire...


Quelle est la différence ?

--drkm

Avatar
Jean-Louis Liagre
Stephane Chazelas wrote:
On Tue, 23 Aug 2005 16:06:49 +0200, Jean-Louis Liagre wrote:
[...]

nawk n'est pas une commande POSIX, et il n'y rien dans cette
commande awk qui ne marcherait pas meme avec le awk originel


Plus précisément, nawk est le awk POSIX sous Solaris
(/usr/xpg4/bin/awk), et surtout, il va beaucoup plus vite.



Non, sous Solaris, nawk est different de /usr/xpg4/bin/awk meme
si /usr/xpg4/bin/awk est plus proche de nawk que de
/usr/bin/awk.


man nawk:

DESCRIPTION
The /usr/bin/nawk and /usr/xpg4/bin/awk utilities execute
programs written in the nawk programming language, which is
specialized for textual data manipulation.

nawk n'est pas POSIX conformant (du moins, moins
que /usr/xpg4/bin/awk) et la commande n'existe pas forcement sur
tous les Unix vu qu'elle n'est pas standardisee.


$LOGFILE n'est pas correct sans ses quotes et sans "--" avant.


Pas quand logfile vaut /var/adm/messages.



Ca depend de la valeur d'IFS. Mais c'est une question de syntaxe
pour moi, pas de "cas particulier".


S'il n'y a pas de "MARK", tu auras une syntax error de sed.


Bien vu.

2ème essai:

#!/bin/ksh
LOGFILE="/var/log/messages"
sed -n "$(grep -n MARK -- "$LOGFILE"||echo 1|tail -1|
awk -F : '{print $1}'),$p" -- "$LOGFILE"




LOGFILE="/var/log/messages"
sed -n "$({ grep -n MARK -- "$LOGFILE"||echo 1;} |tail -1|
awk -F : '{print $1}'),$p" < "$LOGFILE"

Sinon, le tail ne s'applique qu'a echo.


ouch, c'est vrai.

Par contre vous m'avez induit en erreur, la syntaxe que j'utilise
ne passe pas avec /bin/awk sous Solaris (-F et son argument
doivent être collés).

Voici donc quelque chose qui devrait passer:

LOGFILE="/var/log/messages"
sed -n "$({grep -n MARK "$LOGFILE"||echo 1;} |tail -1|
awk -F: '{print $1}'),$p" -- "$LOGFILE"

Et ni /usr/xpg4/bin/awk ni nawk ne supportent "--" sous Solaris.


1) je n'utilise "--" dans mon script qu'avec sed et grep,
et je viens de retirer celui que vous aviez mis au grep, qui ne
passe pas, sous Solaris du moins.

2) Faux, /usr/xpg4/bin/awk et nawk supportent "--" sous Solaris,
d'ailleurs "--" est POSIX. awk (oawk) ne le supporte pas.

$ cat a.awk
{
print $0
print a
}
$ date | awk -f a.awk -- a"
Wed Aug 24 00:45:40 CEST 2005

$ date | awk -f a.awk a"
Wed Aug 24 00:46:03 CEST 2005
22
$ date | nawk -f a.awk -- a"
Wed Aug 24 00:46:11 CEST 2005
22
$ date | /usr/xpg4/bin/awk -f a.awk -- a"
Wed Aug 24 00:46:26 CEST 2005
22


De plus, probleme si les noms de fichiers contiennent des "=",
mieux vaut laisser le shell ouvrir le fichier (l'alternative est
de remplacer les fichiers "fooºr" par "./fooºr").


Je ne vois pas en quoi des fichiers dont les noms contiennent
des "=" perturbent mon script.

$ LOGFILE="a=test"
$ cat /etc/group > $LOGFILE
$ sed -n "$({ grep -n daemon "$LOGFILE"||echo 1;} |tail -1|
nawk -F : '{print $1}'),$p" -- "$LOGFILE"
daemon::12:root
sysadmin::14:
smmsp::25:
gdm::50:
webservd::80:
nobody::60001:
noaccess::60002:
nogroup::65534:
sasl::100:

Qui a dit que le shell etait mieux que perl?


J'ai dit ça moi ?
Ca m'étonnerai. Les deux n'ont rien à voir.



1 2