Expressions Rationnelle

Published: 31-08-2015

Updated: 25-11-2018

By: Maxime de Roucy

tags: perl regex

Je vous encourage vivement à lire les informations du site www.regular-expressions.info. Il est extrèment complet est très bien expliqué.

Non-Capturing Group

(?:xxx|yyy)

C’est une optimisation pour rendre le moteur plus rapide. Ça permet de faire des groups dont le contenu n’est pas sauvegardé.

Source : www.regular-expressions.info

Atomic Grouping

(?>xxx|yyy)

C’est une optimisation pour rendre le moteur plus rapide. Ces group ne sauvegarde pas leur contenu, c’est l’équivalent d’un « non-capturing group » avec des feature en plus.

a(bc|b)c match abcc et abc ; a(>?bc|b)c match abcc mais pas abc.

Ce qui se passe pour abcc avec a(bc|b)c :

Ce qui se passe pour abcc avec a(>?bc|b)c :

Ce qui se passe pour abc avec a(bc|b)c :

Ce qui se passe pour abc avec a(>?bc|b)c :

En résumé, avec les « atomic group », une fois que le moteur d’expression rationnelle sort du group il ne peut plus y retourner. Le traitement est donc plus rapide. Les « atomic group » n’ont pas vraiment d’autre intérêt que celui d’accéléré le traitement d’une regex.

Pour les utilisé comme des « non capturing group » (que ça reviennent à utiliser des « non capturing group ») standard il faut juste s’assurer que les éléments du group ne match pas le début d’un élément situé à leur gauche.

Source : www.regular-expressions.info

Lookahead et Lookbehind

Source : lookaround sur le site www.regular-expressions.info

Les « lookaround » peuvent être considéré comme des sous-regexp à l’intérieur des regexp. Les groups lookaround sont atomic (voir section Atomic Grouping).

Lookahead

Un « Lookahead » s’écrit (?=x) ou x est le caractère recherché.

max@laptop % echo 'aa bb cc' | grep -P -o 'a bb'
a bb
max@laptop % echo 'aa bb cc' | grep -P -o 'a b(?=b)'
a b
max@laptop % echo 'aa bb cc' | grep -P -o 'a b(?=b) c'
max@laptop % echo 'aa bb cc' | grep -P -o 'a b(?=b)b c'
a bb c

Le moteur de recherche d’expression rationnelle parcour la chaîne de caractère à parser (ici « aa bb cc »). Il possède plusieurs curseurs, dont deux qui nous interesse ici :

Le moteur compare l’élément à X+Y dans la chaîne de caractère à parser au caractère Y dans l’expression rationnelle. Exemple avec echo 'aa bb cc' | grep -P -o 'a bb' :

Lorsque Y arrive sur un « Lookahead » c’est comme si un autre moteur d’expression rationnelle prennait le relait temporairement et vérifié que l’expression rationnelle contenu dans le « Lookahead » match la chaîne de caractère commençant à X+Y. Si ça match, le premier moteur reprend le relait et continu comme si rien ne s’été passé. Si ça ne match pas, le premier moteur considère que ça ne match pas, incrémente X et remet Y à 0. Exemple avec echo 'aa bb cc' | grep -P -o 'a b(?=b) c' :

Il est possible de faire des captures dans un « Lookaround » (voir Lookaround Is Atomic).

Negative Lookahead

Un « Negative Lookahead » s’écrit (?!x) ou x est le caractère recherché. Cette fois le moteur continu si le contenu du « Negative Lookahead » ne match pas.

max@laptop % echo 'aa bb cc' | grep -P -o 'a bb'
a bb
max@laptop % echo 'aa bb cc' | grep -P -o 'b(?!b)'
b
max@laptop % echo 'aa bb cc' | grep -P -o ' b(?!b)'
max@laptop % echo 'aa bb cc' | grep -P -o ' b(?!a)'
 b
max@laptop % echo 'aa bb cc' | grep -P -o 'a b(?!a)'
a b
max@laptop % echo 'aa bb cc' | grep -P -o 'a b(?!a)b c'
a bb c

exemple

Source : How do I write a regex for ‘does not contain’ a string

Il est possible via un negative lookehead de faire une regex qui match n’importe quel chaine de caractère ne contenant pas un certain pattern.

^(?:(?!PATTERN).)*$
^(?:[^P]+|P(?!ATTERN))*$

La première regex est lente, la deuxième est plus rapide.

Lookbehind

Un « Lookbehind » s’écrit (?<=x) ou x est le caractère recherché. Il fait à peut près la même chose que le « Lookahead » mais vérifie les caractères précédent.

max@laptop % echo 'aa bb cc' | grep -P -o 'a bb'
a bb
max@laptop % echo 'aa bb cc' | grep -P -o 'b(?<=b)'
b
max@laptop % echo 'aa bb cc' | grep -P -o ' b(?<=b )'
max@laptop % echo 'aa bb cc' | grep -P -o ' b(?<= b)'
b
max@laptop % echo 'aa bb cc' | grep -P -o 'a b(?<=a b)b c'
a bb c
max@laptop % echo 'aa bb cc' | grep -P -o '(?<=a b)b c'
b c

Negative Lookbehind

Un « Negative Lookbehind » s’écrit (?<!x) ou x est le caractère recherché.

max@laptop % echo 'aa bb cc' | grep -P -o 'a bb'
a bb
max@laptop % echo 'aa bb cc' | grep -P -o '(?<!b)b'
b
max@laptop % echo 'aa bb cc' | grep -P -o '(?<!b)bb'
bb
max@laptop % echo 'aa bb cc' | grep -P -o '(?<! )bb'
max@laptop % echo 'aa bb cc' | grep -P -o '(?<![abcd])bb c'
bb c
max@laptop % echo 'aa bb cc' | grep -P -o '(?<![abcd ])bb c'

quantifier

greedy

Par défaut les quantifier (*, +, ?, {n}, {n,}, {n,m}) sont « greedy », c’est à dire qu’il cherche à prendre le plus de caractère possible. Si deux quantifier sont utilisé dans une regex, le premier est considéré comme plus greedy que le second :

max@laptop % echo 'aaaa' | perl -nle '/.*(a*)/ and print "match: $1"'
match:
max@laptop % echo 'aaaa' | perl -nle '/(a*)/ and print "match: $1"'
match: aaaa

lazy

Pour indiquer qu’un délimiteur est non greedy, il faut ajouter un ? à sa suite :

max@laptop % echo 'aaaa' | perl -nle '/.*?(a*)/ and print "match: $1"'
match: aaaa
max@laptop % echo 'aaaa' | perl -nle '/.*?(a*?)/ and print "match: $1"'
match:

possessive

Un quantifier est possessive s’il est suivit du caractère « + » (e.g. *+, ++…).

Par rapport à un quantifier standard, un quantifier possessive indique au moteur de regex de ne pas enregistré les états intermédiaires. Lorsque le moteur trouve un match pour le quantifier il passe aux prochains éléments à chercher mais ne revient pas en arrière si la suite de la regex ne match pas.

max@laptop % echo '@abc@' | perl -nle '/@(.*)@/ and print "match: $1"'
match: abc
max@laptop % echo '@abc@' | perl -nle '/@(.*+)@/ and print "match: $1"'

Lors de la recherche de .* et .*+ le moteur à trouvé abc@, mais lorsqu’il est passé à la recherche de @ il ne l’a pas trouvé. Dans le cas .*, le moteur est revenu en arrière est à réessayé en considérant que .* == abc (et non plus abc@). Dans le cas .*+ le moteur ne revient pas en arrière.

Je ne vois pas d’autres intérêts au possessive quantifier que celui d’accéler le moteur de regex.

[]

Source : man perlre

Un ensemble de caractère regroupé entre des crochets [] s’appel une liste (dans les expression rationel perl).

Si ^ (circumflex) est le premier caractère suivant le [, la liste match tous les caractère excepté ceux contenu entre les [] (sauf le ^).

[…] if the first character after the "[" is "^", the class matches any character not in the list.

Un - (hyphen) désigne un “range” sauf s’il est placé juste après le [, avant le ] ou qu’il est échapé par un \ (backslash).

Within a list, the "-" character specifies a range of characters, so that a-z represents all characters between “a” and “z”, inclusive. If you want either "-" or "]" itself to be a member of a class, put it at the start of the list (possibly after a "^"), or escape it with a backslash. "-" is also taken literally when it is at the end of the list, just before the closing "]".

special match

\w
shortcut pour [A-Za-z0-9_]
\s
whitespace, shortcut pour [ \f\n\r\t]
\d
décimal, shortcut pour [0-9]
\b
délimiteur de mot (word boundaries). match de taille nulle.
\B
tout sauf \b, match de taille nulle.

perl

Les expressions rationnelles (regex) de perl sont beaucoup plus complêtes que celles utilisée via grep et sed. De plus perl permet de faire des remplacement/recherche sur plusieurs lignes, ce qui est possible mais très compliqué avec grep et sed.

En ce qui concernes les bases de la programation perl, le site linuxtricks contient un bon memo.

Manuel des options de la commande perl : man perlrun

Manuel des expressions rationnelles de perl : man perlre

remplacer grep par perl

Pour remplacer grep par perl j’utilise l’une des commandes suivantes :

max@laptop % perl -lne '/ma_regex/ and print' mon_fichier
max@laptop % perl -lne '/ma_regex/ and print' mon_fichier
max@laptop % perl -lne 'print if /ma_regex/' mon_fichier

Source : stackoverflow.com

remplacer sed par perl

Pour remplacer sed par perl j’utilise la commande suivante :

max@laptop % perl -pe 's/ma_regex/ma_substitution/' mon_fichier

Source : herverenault.fr

remplacer awk par perl

Pour remplacer awk par perl j’utilise la commande suivante :

max@laptop % echo 'a b  c d' | perl -alne 'print $F[2]'
c

multiple match

Pour rechercher un même paterne plusieurs fois sur la même ligne et afficher les résultat sur plusieurs ligne.

max@laptop % cat monfichier
maregex1 aaa maregex2 bbb ccc maregex3 ddd
max@laptop % perl -n -e 'foreach my $i (/maregex./g) { print $i."\n" }' monfichier
maregex1
maregex2
maregex3

Source : perldoc – perlsyn : Foreach-Loops

modifier

Il est possible d’appliquer des modifier au regex via la ligne de commande.

max@laptop % perl -Mre='/a' -ne '…'

Par exemple, le modifier /a (section « /a (and /aa) ») permet de restraindre les expression régulière à l’ASCII. En UTF-8 \w match plus de 100 000 de caractères, alors qu’avec /a, \w = [A-Za-z0-9_].

.. et …

Ce sont des tests « fip-flop », il possède et conserve un booleen interne donnant la valeur de ce test. Ce booleen est passé à true si le test de gauche est à true, il est passé à false si le test de gauche est à true.

The original three dot operator is another flip-flop operator. And the difference between it and the two dot version is subtle. It’s all to do with how many tests can be run against the same line. With the two dot version, when the operator flips to true it also checks the right-hand operand in the same iteration – meaning that it can flip from false to true and back to false again as part of the same iteration. If you use the three dot version, then once the operator flips to true, then it won’t check the right-hand operand until the next iteration – meaning that the operator can only flip once per iteration.

Exemple :

max@laptop % cat A
a
b
c
d
max@laptop % perl -ne 'print if /b/.../c/' A
b
c
max@laptop % perl -ne 'print if /b/.../d/' A
b
c
d

Source : opérateur .. et … en perl

plusieurs fichiers

Attentions lorsque la syntax /…/ ... /…/ est utilisé avec plusieurs fichier en paramètre. Lors du passage d’un fichier à l’autre, les compteurs ne sont pas remis à zéro.

max@laptop % cat A && cp A B
a
b
c
d
max@laptop % perl -ne 'print if /b/...0' A B
b
c
d
a
b
c
d
max@laptop % perl -ne 'print if /b/.../z/' A B
b
c
d
a
b
c
d

&& || vs and or

Sources :

As alternatives to “&&” and “||” when used for control flow, Perl provides the “and” and “or” operators (see below). The short-circuit behavior is identical. The precedence of “and” and “or” is much lower, however, so that you can safely use them after a list operator without the need for parentheses

&& et || ont des précédences beaucoup plus grande que and et or.

max@laptop % echo -en 'a\ntruc\nb\n' | perl -ne 'print if ( /a/.../b/ && /truc/ )'
a
truc
b
max@laptop % echo -en 'a\ntruc\nb\n' | perl -ne 'print if ( /a/.../b/ and /truc/ )'
truc

Dans le premier exemple, le test effectué était en fait /a/ ... ( /b/ && /truc/ ) ; la précédence de && est plus grande que celle de ....

access.log

J’utilise pour cet exemple le log_format suivant.

log_format main
    '$remote_addr - $remote_user [$time_local] '
    '"$request" $status $bytes_sent - Time Taken $request_time '
    '"$http_referer" "$http_user_agent" '
    '"$gzip_ratio"';

Un extrait de mes logs. J’utilise journalctl mais je pourrait aussi utiliser un fichier access.log, ça fonctionne de la même façon.

max@server % day=`LC_ALL=C date '+%d\/%b\/%Y'`
max@server % journalctl -u nginx.service -q --since='2016-09-09 17:02:49'
sept. 09 17:02:49 server nginx[14813]: server nginx: 91.208.181.161 - - [09/Sep/2016:17:02:49 +0200] "GET /theme/css/main.css HTTP/2.0" 200 2499 - Time Taken 0.000 "https://pelican.craoc.fr/expressions-rat
sept. 09 17:02:49 server nginx[14813]: server nginx: 91.208.181.161 - - [09/Sep/2016:17:02:49 +0200] "GET /theme/tipuesearch/tipuesearch.css HTTP/2.0" 200 1086 - Time Taken 0.000 "https://pelican.craoc.fr/
sept. 09 17:02:49 server nginx[14813]: server nginx: 91.208.181.161 - - [09/Sep/2016:17:02:49 +0200] "GET /theme/css/reset.css HTTP/2.0" 200 821 - Time Taken 0.000 "https://pelican.craoc.fr/theme/css/main.
sept. 09 17:02:49 server nginx[14813]: server nginx: 91.208.181.161 - - [09/Sep/2016:17:02:49 +0200] "GET /theme/css/pygment.css HTTP/2.0" 200 612 - Time Taken 0.000 "https://pelican.craoc.fr/theme/css/mai
sept. 09 17:02:49 server nginx[14813]: server nginx: 91.208.181.161 - - [09/Sep/2016:17:02:49 +0200] "GET /theme/fonts/fonts.css HTTP/2.0" 200 490 - Time Taken 0.000 "https://pelican.craoc.fr/theme/css/mai
sept. 09 17:02:51 server nginx[14813]: server nginx: 91.208.181.161 - - [09/Sep/2016:17:02:51 +0200] "GET /expressions-rationnel.html HTTP/2.0" 200 3653 - Time Taken 0.000 "https://pelican.craoc.fr/search.
sept. 09 17:02:51 server nginx[14813]: server nginx: 91.208.181.161 - - [09/Sep/2016:17:02:51 +0200] "GET /theme/css/main.css HTTP/2.0" 200 2499 - Time Taken 0.000 "https://pelican.craoc.fr/expressions-rat
sept. 09 17:02:51 server nginx[14813]: server nginx: 91.208.181.161 - - [09/Sep/2016:17:02:51 +0200] "GET /theme/tipuesearch/tipuesearch.css HTTP/2.0" 200 1086 - Time Taken 0.000 "https://pelican.craoc.fr/
sept. 09 17:02:51 server nginx[14813]: server nginx: 91.208.181.161 - - [09/Sep/2016:17:02:51 +0200] "GET /theme/css/reset.css HTTP/2.0" 200 821 - Time Taken 0.000 "https://pelican.craoc.fr/theme/css/main.
sept. 09 17:02:51 server nginx[14813]: server nginx: 91.208.181.161 - - [09/Sep/2016:17:02:51 +0200] "GET /theme/css/pygment.css HTTP/2.0" 200 612 - Time Taken 0.000 "https://pelican.craoc.fr/theme/css/mai
sept. 09 17:02:51 server nginx[14813]: server nginx: 91.208.181.161 - - [09/Sep/2016:17:02:51 +0200] "GET /theme/fonts/fonts.css HTTP/2.0" 200 490 - Time Taken 0.000 "https://pelican.craoc.fr/theme/css/mai
sept. 09 17:06:51 server nginx[14813]: server nginx: 163.172.65.186 - - [09/Sep/2016:17:06:51 +0200] "GET /doku.php?id=archlinux_install&do=recent HTTP/1.1" 200 4365 - Time Taken 0.087 "-" "Mozilla/5.0 (co
sept. 09 17:09:44 server nginx[14813]: server nginx: 51.255.65.40 - - [09/Sep/2016:17:09:44 +0200] "GET /doku.php?id=udev&tab_details=history&do=media&tab_files=search&image=tot_a_rembourser.gif&ns=wiki HT
sept. 09 17:09:44 server nginx[14813]: server nginx: 163.172.65.34 - - [09/Sep/2016:17:09:44 +0200] "GET /doku.php?id=webapp-config&tab_details=history&do=media&tab_files=upload&image=mensualite.gif&ns=imm
sept. 09 17:11:34 server nginx[14813]: server nginx: 163.172.66.114 - - [09/Sep/2016:17:11:34 +0200] "GET /doku.php?id=rootkit&image=wiki%3Adokuwiki-128.png&tab_details=view&do=media&tab_files=upload&ns= H
sept. 09 17:12:31 server nginx[14813]: server nginx: 91.208.181.161 - - [09/Sep/2016:17:12:31 +0200] "GET / HTTP/2.0" 200 9136 - Time Taken 0.000 "https://pelican.craoc.fr/expressions-rationnel.html" "Mozi
sept. 09 17:12:31 server nginx[14813]: server nginx: 91.208.181.161 - - [09/Sep/2016:17:12:31 +0200] "GET /theme/css/main.css HTTP/2.0" 200 2499 - Time Taken 0.000 "https://pelican.craoc.fr/" "Mozilla/5.0
sept. 09 17:12:31 server nginx[14813]: server nginx: 91.208.181.161 - - [09/Sep/2016:17:12:31 +0200] "GET /theme/tipuesearch/tipuesearch.css HTTP/2.0" 200 1086 - Time Taken 0.000 "https://pelican.craoc.fr/
sept. 09 17:12:32 server nginx[14813]: server nginx: 91.208.181.161 - - [09/Sep/2016:17:12:32 +0200] "GET /theme/css/reset.css HTTP/2.0" 200 821 - Time Taken 0.000 "https://pelican.craoc.fr/theme/css/main.
sept. 09 17:12:32 server nginx[14813]: server nginx: 91.208.181.161 - - [09/Sep/2016:17:12:32 +0200] "GET /theme/css/pygment.css HTTP/2.0" 200 612 - Time Taken 0.000 "https://pelican.craoc.fr/theme/css/mai
sept. 09 17:12:32 server nginx[14813]: server nginx: 91.208.181.161 - - [09/Sep/2016:17:12:32 +0200] "GET /theme/fonts/fonts.css HTTP/2.0" 200 490 - Time Taken 0.000 "https://pelican.craoc.fr/theme/css/mai
sept. 09 17:18:45 server nginx[14813]: server nginx: 91.208.181.163 - max [09/Sep/2016:17:18:45 +0200] "PROPFIND /caldav.php/max/cal_perso/ HTTP/1.1" 207 765 - Time Taken 0.087 "-" "Evolution/3.20.5" "-"
sept. 09 17:18:45 server nginx[14813]: server nginx: 91.208.181.163 - max [09/Sep/2016:17:18:45 +0200] "PROPFIND /caldav.php/max/cal_job/ HTTP/1.1" 207 763 - Time Taken 0.081 "-" "Evolution/3.20.5" "-"
sept. 09 17:18:45 server nginx[14813]: server nginx: 91.208.181.163 - max [09/Sep/2016:17:18:45 +0200] "PROPFIND /caldav.php/max/cal_perso/ HTTP/1.1" 207 765 - Time Taken 0.086 "-" "Evolution/3.20.5" "-"
sept. 09 17:18:45 server nginx[14813]: server nginx: 91.208.181.163 - max [09/Sep/2016:17:18:45 +0200] "PROPFIND /caldav.php/max/cal_job/ HTTP/1.1" 207 763 - Time Taken 0.092 "-" "Evolution/3.20.5" "-"
sept. 09 17:18:52 server nginx[14813]: server nginx: 164.132.161.24 - - [09/Sep/2016:17:18:52 +0200] "GET /doku.php?id=gnome:login&tab_details=history&do=media&tab_files=upload&image=template.pcp&ns=wiki H
sept. 09 17:20:00 server nginx[14813]: server nginx: 163.172.64.228 - - [09/Sep/2016:17:20:00 +0200] "GET /doku.php?id=vagrant&do=diff&rev2%5B0%5D=1385628834&rev2%5B1%5D=1410358333&difftype=sidebyside HTTP

Log entre 17h et 17h10 :

max@server % day=`LC_ALL=C date '+%d\/%b\/%Y'`
max@server % journalctl -u nginx.service -q --since='2016-09-09 17:02:49' | perl -n -e 'if (/'$day':17:0/ ... /'$day':17:1/) { print "$_" ; }'
sept. 09 17:02:49 server nginx[14813]: server nginx: 91.208.181.161 - - [09/Sep/2016:17:02:49 +0200] "GET /theme/css/main.css HTTP/2.0" 200 2499 - Time Taken 0.000 "https://pelican.craoc.fr/expressions-rationnel.html" "Mozilla/5.0 (X11; Linux x86_64; rv:48.0) Gecko/20100101 Firefox/48.0" "-"
sept. 09 17:02:49 server nginx[14813]: server nginx: 91.208.181.161 - - [09/Sep/2016:17:02:49 +0200] "GET /theme/tipuesearch/tipuesearch.css HTTP/2.0" 200 1086 - Time Taken 0.000 "https://pelican.craoc.fr/expressions-rationnel.html" "Mozilla/5.0 (X11; Linux x86_64; rv:48.0) Gecko/20100101 Firefox/48.0" "-"
sept. 09 17:02:49 server nginx[14813]: server nginx: 91.208.181.161 - - [09/Sep/2016:17:02:49 +0200] "GET /theme/css/reset.css HTTP/2.0" 200 821 - Time Taken 0.000 "https://pelican.craoc.fr/theme/css/main.css" "Mozilla/5.0 (X11; Linux x86_64; rv:48.0) Gecko/20100101 Firefox/48.0" "-"
sept. 09 17:02:49 server nginx[14813]: server nginx: 91.208.181.161 - - [09/Sep/2016:17:02:49 +0200] "GET /theme/css/pygment.css HTTP/2.0" 200 612 - Time Taken 0.000 "https://pelican.craoc.fr/theme/css/main.css" "Mozilla/5.0 (X11; Linux x86_64; rv:48.0) Gecko/20100101 Firefox/48.0" "-"
sept. 09 17:02:49 server nginx[14813]: server nginx: 91.208.181.161 - - [09/Sep/2016:17:02:49 +0200] "GET /theme/fonts/fonts.css HTTP/2.0" 200 490 - Time Taken 0.000 "https://pelican.craoc.fr/theme/css/main.css" "Mozilla/5.0 (X11; Linux x86_64; rv:48.0) Gecko/20100101 Firefox/48.0" "-"
sept. 09 17:02:51 server nginx[14813]: server nginx: 91.208.181.161 - - [09/Sep/2016:17:02:51 +0200] "GET /expressions-rationnel.html HTTP/2.0" 200 3653 - Time Taken 0.000 "https://pelican.craoc.fr/search.html?q=perl" "Mozilla/5.0 (X11; Linux x86_64; rv:48.0) Gecko/20100101 Firefox/48.0" "-"
sept. 09 17:02:51 server nginx[14813]: server nginx: 91.208.181.161 - - [09/Sep/2016:17:02:51 +0200] "GET /theme/css/main.css HTTP/2.0" 200 2499 - Time Taken 0.000 "https://pelican.craoc.fr/expressions-rationnel.html" "Mozilla/5.0 (X11; Linux x86_64; rv:48.0) Gecko/20100101 Firefox/48.0" "-"
sept. 09 17:02:51 server nginx[14813]: server nginx: 91.208.181.161 - - [09/Sep/2016:17:02:51 +0200] "GET /theme/tipuesearch/tipuesearch.css HTTP/2.0" 200 1086 - Time Taken 0.000 "https://pelican.craoc.fr/expressions-rationnel.html" "Mozilla/5.0 (X11; Linux x86_64; rv:48.0) Gecko/20100101 Firefox/48.0" "-"
sept. 09 17:02:51 server nginx[14813]: server nginx: 91.208.181.161 - - [09/Sep/2016:17:02:51 +0200] "GET /theme/css/reset.css HTTP/2.0" 200 821 - Time Taken 0.000 "https://pelican.craoc.fr/theme/css/main.css" "Mozilla/5.0 (X11; Linux x86_64; rv:48.0) Gecko/20100101 Firefox/48.0" "-"
sept. 09 17:02:51 server nginx[14813]: server nginx: 91.208.181.161 - - [09/Sep/2016:17:02:51 +0200] "GET /theme/css/pygment.css HTTP/2.0" 200 612 - Time Taken 0.000 "https://pelican.craoc.fr/theme/css/main.css" "Mozilla/5.0 (X11; Linux x86_64; rv:48.0) Gecko/20100101 Firefox/48.0" "-"
sept. 09 17:02:51 server nginx[14813]: server nginx: 91.208.181.161 - - [09/Sep/2016:17:02:51 +0200] "GET /theme/fonts/fonts.css HTTP/2.0" 200 490 - Time Taken 0.000 "https://pelican.craoc.fr/theme/css/main.css" "Mozilla/5.0 (X11; Linux x86_64; rv:48.0) Gecko/20100101 Firefox/48.0" "-"
sept. 09 17:06:51 server nginx[14813]: server nginx: 163.172.65.186 - - [09/Sep/2016:17:06:51 +0200] "GET /doku.php?id=archlinux_install&do=recent HTTP/1.1" 200 4365 - Time Taken 0.087 "-" "Mozilla/5.0 (compatible; AhrefsBot/5.1; +http://ahrefs.com/robot/)" "5.01"
sept. 09 17:09:44 server nginx[14813]: server nginx: 51.255.65.40 - - [09/Sep/2016:17:09:44 +0200] "GET /doku.php?id=udev&tab_details=history&do=media&tab_files=search&image=tot_a_rembourser.gif&ns=wiki HTTP/1.1" 200 4413 - Time Taken 0.067 "-" "Mozilla/5.0 (compatible; AhrefsBot/5.1; +http://ahrefs.com/robot/)" "3.72"
sept. 09 17:09:44 server nginx[14813]: server nginx: 163.172.65.34 - - [09/Sep/2016:17:09:44 +0200] "GET /doku.php?id=webapp-config&tab_details=history&do=media&tab_files=upload&image=mensualite.gif&ns=immobilier HTTP/1.1" 200 4115 - Time Taken 0.057 "-" "Mozilla/5.0 (compatible; AhrefsBot/5.1; +http://ahrefs.com/robot/)" "3.60"
sept. 09 17:11:34 server nginx[14813]: server nginx: 163.172.66.114 - - [09/Sep/2016:17:11:34 +0200] "GET /doku.php?id=rootkit&image=wiki%3Adokuwiki-128.png&tab_details=view&do=media&tab_files=upload&ns= HTTP/1.1" 200 3966 - Time Taken 0.060 "-" "Mozilla/5.0 (compatible; AhrefsBot/5.1; +http://ahrefs.com/robot/)" "3.43"

Requêtes entre 17h et 17h10 :

max@server % day=`LC_ALL=C date '+%d\/%b\/%Y'`
max@server % journalctl -u nginx.service -q --since='2016-09-09 17:02:49' | perl -n -e 'if (/'$day':17:0/ ... /'$day':17:1/ and /GET ([^ ]*)/) { print "$1\n" ; }'
/theme/css/main.css
/theme/tipuesearch/tipuesearch.css
/theme/css/reset.css
/theme/css/pygment.css
/theme/fonts/fonts.css
/expressions-rationnel.html
/theme/css/main.css
/theme/tipuesearch/tipuesearch.css
/theme/css/reset.css
/theme/css/pygment.css
/theme/fonts/fonts.css
/doku.php?id=archlinux_install&do=recent
/doku.php?id=udev&tab_details=history&do=media&tab_files=search&image=tot_a_rembourser.gif&ns=wiki
/doku.php?id=webapp-config&tab_details=history&do=media&tab_files=upload&image=mensualite.gif&ns=immobilier
/doku.php?id=rootkit&image=wiki%3Adokuwiki-128.png&tab_details=view&do=media&tab_files=upload&ns=

Requêtes à partir de 17h :

max@server % day=`LC_ALL=C date '+%d\/%b\/%Y'`
max@server % journalctl -u nginx.service -q --since='2016-09-09 17:02:49' | perl -n -e 'if (/'$day':17/ ... 0 and /GET ([^ ]*)/) { print "$1\n" ; }'
/theme/css/main.css
/theme/tipuesearch/tipuesearch.css
/theme/css/reset.css
/theme/css/pygment.css
/theme/fonts/fonts.css
/expressions-rationnel.html
/theme/css/main.css
/theme/tipuesearch/tipuesearch.css
/theme/css/reset.css
/theme/css/pygment.css
/theme/fonts/fonts.css
/doku.php?id=archlinux_install&do=recent
/doku.php?id=udev&tab_details=history&do=media&tab_files=search&image=tot_a_rembourser.gif&ns=wiki
/doku.php?id=webapp-config&tab_details=history&do=media&tab_files=upload&image=mensualite.gif&ns=immobilier
/doku.php?id=rootkit&image=wiki%3Adokuwiki-128.png&tab_details=view&do=media&tab_files=upload&ns=
/
/theme/css/main.css
/theme/tipuesearch/tipuesearch.css
/theme/css/reset.css
/theme/css/pygment.css
/theme/fonts/fonts.css
/doku.php?id=gnome:login&tab_details=history&do=media&tab_files=upload&image=template.pcp&ns=wiki
/doku.php?id=vagrant&do=diff&rev2%5B0%5D=1385628834&rev2%5B1%5D=1410358333&difftype=sidebyside

Requêtes entre 17h et 17h10, trié par nomble d’occurance :

max@server % day=`LC_ALL=C date '+%d\/%b\/%Y'`
max@server % journalctl -u nginx.service -q --since='2016-09-09 17:02:49' | perl -n -e 'if (/'$day':17:0/ ... /'$day':17:1/ and /GET ([^ ]*)/) { print "$1\n" ; }' | sort | uniq -c | sort | tail
      1 /doku.php?id=archlinux_install&do=recent
      1 /doku.php?id=rootkit&image=wiki%3Adokuwiki-128.png&tab_details=view&do=media&tab_files=upload&ns=
      1 /doku.php?id=udev&tab_details=history&do=media&tab_files=search&image=tot_a_rembourser.gif&ns=wiki
      1 /doku.php?id=webapp-config&tab_details=history&do=media&tab_files=upload&image=mensualite.gif&ns=immobilier
      1 /expressions-rationnel.html
      2 /theme/css/main.css
      2 /theme/css/pygment.css
      2 /theme/css/reset.css
      2 /theme/fonts/fonts.css
      2 /theme/tipuesearch/tipuesearch.css

Requêtes entre 17h et 17h10, trié par temps de traitement :

max@server % day=`LC_ALL=C date '+%d\/%b\/%Y'`
max@server % journalctl -u nginx.service -q --since='2016-09-09 17:02:49' | perl -n -e 'if (/'$day':17:0/ ... /'$day':17:1/ and /GET ([^ ]*) .* Time Taken ([\d\.]*) /) { print "$1 $2\n" ; }' | sort -k 2 | tail
/theme/css/reset.css 0.000
/theme/css/reset.css 0.000
/theme/fonts/fonts.css 0.000
/theme/fonts/fonts.css 0.000
/theme/tipuesearch/tipuesearch.css 0.000
/theme/tipuesearch/tipuesearch.css 0.000
/doku.php?id=webapp-config&tab_details=history&do=media&tab_files=upload&image=mensualite.gif&ns=immobilier 0.057
/doku.php?id=rootkit&image=wiki%3Adokuwiki-128.png&tab_details=view&do=media&tab_files=upload&ns= 0.060
/doku.php?id=udev&tab_details=history&do=media&tab_files=search&image=tot_a_rembourser.gif&ns=wiki 0.067
/doku.php?id=archlinux_install&do=recent 0.087

sort

Attention à la commande sort, il faut parfois utiliser l’option ‘-h’ (penser aussi à la locale LC_COLLATE).

max@laptop % export LC_ALL=C
max@laptop % echo -e '11\n 9'| sort
 9
11
max@laptop % echo -e '11\n9'| sort
11
9
max@laptop % echo -e '11\n9.5'| sort
11
9.5
max@laptop % echo -e '11\n 9'| sort -h
 9
11
max@laptop % echo -e '11\n9'| sort -h
9
11
max@laptop % echo -e '11\n9.5'| sort -h
9.5
11