Checkmk
to checkmk.com

1. Einleitung

Reguläre Ausdrücke (englisch regular expression oder regex, selten regexp), werden in Checkmk für die Angabe von Service-Namen und auch an vielen anderen Stellen verwendet. Es sind Muster, die auf einen bestimmten Text passen (match) oder nicht passen (nonmatch). Damit können Sie viele praktische Dinge anstellen, wie z.B. flexible Regeln formulieren, die für alle Services greifen, bei denen foo oder bar im Namen vorkommt.

Oft werden reguläre Ausdrücke mit den Suchmustern für Dateinamen verwechselt, denn die Sonderzeichen * und ?, sowie eckige und geschweifte Klammern gibt es in beiden.

In diesem Artikel zeigen wir Ihnen die wichtigsten Möglichkeiten der regulären Ausdrücke, selbstverständlich im Kontext von Checkmk. Da Checkmk zwei verschiedene Komponenten für reguläre Ausdrücke nutzt, steckt manchmal der Teufel im Detail. Im wesentlichen nutzt der Monitoring-Kern die C-Bibliothek und alle weiteren Komponenten Python 3. Wo Unterschiede bestehen, erklären wir diese.

Tipp: In Checkmk sind regexp in Eingabefeldern auf unterschiedlichen Seiten erlaubt. Wenn Sie sich unsicher sind, lassen Sie sich die kontextsensitive Hilfe über das Help-Menü einblenden (Help > Show inline help). Dann sehen Sie, ob reguläre Ausdrücke erlaubt sind und wie sie genutzt werden können.

Bei der Arbeit mit älteren Plugins oder Plugins aus externen Quellen kann es mitunter vorkommen, dass diese Python 2 oder Perl nutzen und von den hier geschilderten Konventionen abweichen, bitte beachten Sie daher die jeweilige Plugin-spezifische Dokumentation.

In diesem Artikel zeigen wir Ihnen die wichtigsten Möglichkeiten der regulären Ausdrücke — aber bei weitem nicht alle. Falls Ihnen die hier gezeigten Möglichkeiten nicht weit genug gehen, finden Sie weiter unten Hinweise, wo Sie alle Details nachlesen können. Und dann gibt es ja immer noch das Internet.

Falls Sie eigene Plugins programmieren wollen, die beispielsweise mit regulären Ausdrücken Auffälligkeiten in Log-Dateien finden, können Sie diesen Artikel als Grundlage verwenden. Allerdings ist bei der Suche in großen Datenmengen die Optimierung der Performance ein wichtiger Aspekt. Schlagen Sie daher im Zweifel immer in der Dokumentation der verwendeten Regex-Bibliothek nach.

2. Mit regulären Ausdrücken arbeiten

In diesem Abschnitt zeigen wir anhand konkreter Beispiele die Arbeit mit regulären Ausdrücken, von einfachen Matches einzelner Zeichen oder Zeichenketten, bis hin zu komplexen Gruppen von Zeichen.

2.1. Alphanumerische Zeichen

Bei den regulären Ausdrücken geht es immer darum, ob ein Muster ("Pattern", beziehungsweise der reguläre Ausdruck) auf einen bestimmten Text (z.B. einen Service-Namen) passt (matcht). Der einfachste Anwendungsfall sind Ketten alphanumerischer Zeichen. Diese (und das als Bindestrich verwendete Minus-Zeichen) im Ausdruck matchen einfach sich selbst.

In der Suche des Monitorings unterscheidet Checkmk dabei in der Regel nicht zwischen Groß- und Kleinschreibung. Der Ausdruck CPU load matcht also in den meisten Fällen auf den Text CPU load genauso wie auf cpu LoAd. Im Setup dagegen wird üblicherweise zwischen Groß- und Kleinschreibung unterschieden. Begründete Ausnahmen von diesen Standards sind möglich und werden in der Inline-Hilfe beschrieben.

Achtung: Bei Eingabefeldern, in denen ohne reguläre Ausdrücke ein exakter Match vorgesehen ist (meistens bei Host-Namen), wird Groß- und Kleinschreibung immer unterschieden!

2.2. Der Punkt als Wildcard

Neben den "Klartext"-Zeichenketten gibt es eine Reihe von Zeichen und Zeichenfolgen, die "magische" Bedeutung haben. Das wichtigste derartige Zeichen ist der . (Punkt). Er matcht genau ein einziges beliebiges Zeichen:

Regulärer AusdruckMatchKein Match

Me.er

Meier
Meyer

Meyyer

.var.log

1var2log
/var/log

/var//log

2.3. Wiederholungen von Zeichen

Sehr häufig möchte man definieren, dass eine Folge von Zeichen bestimmter Länge vorkommen darf. Hierfür gibt man in geschweiften Klammern die Zahl der Wiederholungen des vorhergehenden Zeichens an:

Regulärer AusdruckBedeutungMatchKein Match

Ax{2,5}B

x tritt mindestens zweimal, aber höchstens fünfmal auf

AxxB
AxxxxB

AxB
AxxxxxxB

Ax{0,5}B

x tritt höchstens fünfmal auf, es muss aber nicht auftreten

AB
AxxxxxB

AxxxxxxB

Ax{3}B

x tritt genau dreimal auf

AxxxB

AxxB
AxxxxB

Ax{0,}B

x tritt beliebig oft auf

AB
AxxxxxxB

Ax{1,}B

x tritt mindestens einmal auf

AxB
AxxxxxB

AB

Ax{0,1}B

x tritt höchstens einmal auf

AB
AxB

AxxB

Für die letzten drei Fälle gibt es Abkürzungen: * matcht das vorhergehende Zeichen beliebig oft, + matcht ein mindestens einmaliges Auftreten und ? matcht das höchstens einmalige Auftreten.

Sie können auch den Punkt . mit den Wiederholungsoperatoren verknüpfen, um eine Folge beliebiger Zeichen definierter zu suchen:

Regulärer AusdruckMatchKein Match

State.*OK

State is OK
State = OK
StateOK

StatOK

State*OK

StateOK
StatOK

State OK

a *= *5

a=5
a = 5

a==5

State.+OK

State is OK
State=OK
State OK

StateOK

State.?OK

State=OK
State OK
StateOK

State is OK

2.4. Zeichenklassen, Ziffern und Buchstaben

Zeichenklassen erlauben es, bestimmte Ausschnitte des Zeichensatzes zu matchen, beispielsweise "hier muss eine Ziffer kommen". Dafür setzen Sie alle zu matchenden Zeichen innerhalb eckiger Klammern. Mit einem Minuszeichen können Sie auch Bereiche angeben. Achtung: es gilt dabei die Reihenfolge im 7-Bit-ASCII-Zeichensatz.

So steht beispielsweise [abc] für genau eines der Zeichen a, b oder c und [0-9] für eine beliebige Ziffer - beides lässt sich kombinieren. Auch eine Negation des Ganzen ist möglich: Mit einem ^ in der Klammer steht [^abc] dann für ein beliebiges Zeichen außer a, b, c.

Zeichenklassen lassen sich natürlich mit anderen Operatoren kombinieren. Zunächst mal einige abstrakte Beispiele:

ZeichenklasseBedeutung

[abc]

Genau eines der Zeichen a, b, c.

[0-9a-z_]

Genau eine Ziffer, ein Kleinbuchstabe oder ein Unterstrich.

[^abc]

Jedes beliebige Zeichen außer a, b, c.

[ --]

Genau ein Zeichen aus dem Bereich von Leerzeichen bis Bindestrich gemäß ASCII-Tabelle. In diesem Bereich befinden sich die folgenden Zeichen: !"#$%&'()*+,.

[0-9a-z]{1,20}

Eine Folge von mindestens einem und maximal 20 Buchstaben und/oder Ziffern in beliebiger Reihenfolge.

Dazu einige praktische Beispiele:

Regulärer AusdruckMatchKein Match

[0-7]

0
5

9

[0-7]{2}

00
53

183

M[ae]{1}[iy]{1}e?r

Meier
Meyer
Mayr

Myers

myhost_[0-9a-z_]{3}

myhost_1a3
myhost_1_5

myhost_xy

[+0-9/ ()-]+

+49 89 998209700
089 / 9982 097-00

089 : 9982 097-00
(hier wird nur die Gruppe vor dem Doppelpunkt gematcht)

Hinweis: Wenn Sie eines der Zeichen - oder [] brauchen, müssen Sie etwas tricksen. Das - (Minuszeichen) schreiben Sie ans Ende der Klasse — wie im letzten Beispiel bereits gezeigt. Beim Auswerten der regulären Ausdrücke wird das Minuszeichen, wenn es nicht mittleres von drei Zeichen ist, nicht als Operator, sondern als exakt dieses Zeichen ausgewertet. Eine schließende eckige Klammer platzieren Sie als erstes Zeichen in der Klasse, eine öffnende gegebenenfalls als zweites Zeichen. Da keine leeren Klassen erlaubt sind, wird die schließende eckige Klammer dann als normales Zeichen interpretiert. Eine Klasse mit diesen Sonderzeichen sähe also so aus: []-], beziehungsweise [][-] wenn auch die öffnende eckige Klammer benötigt wird.

2.5. Anfang und Ende — Präfix, Suffix und Infix

In vielen Fällen ist es erforderlich, zwischen Matches am Anfang, am Ende oder einfach irgendwo innerhalb einer Zeichenkette zu unterscheiden. Für den Match des Anfangs einer Zeichenkette (Präfix-Match) verwenden Sie den ^ (Zirkumflex), für das Ende (Suffix-Match) das $ (Dollarzeichen). Ist keines der beiden Zeichen angegeben, ist bei den meisten Bibliotheken für reguläre Ausdrücke Infix-Match Standard — es wird an beliebiger Stelle in der Zeichenkette gesucht. Für exakte Matches verwenden Sie sowohl ^ als auch $.

Regulärer AusdruckMatchKein Match

/var

/var
/var/log
/usr/var

^/var

/var
/var/log

/usr/var

/var$

/var
/usr/var

/var/log

^/var$

/var

/var/log
/usr/var

Hinweis: Im Monitoring und der Event Console ist Infix-Match Standard. Ausdrücke, die irgendwo im Text vorkommen, werden gefunden, die Suche nach "memory" findet auch "Kernel memory". In der Setup-GUI dagegen prüft Checkmk beim Vergleichen von regulären Ausdrücken mit Service-Namen und anderen Dingen grundsätzlich, ob der Ausdruck mit dem Anfang des Textes übereinstimmt (Präfix-Match) – in der Regel ist dies, was Sie suchen:

regexes servicematch

Falls Sie an Stellen, an denen Präfix-Match vorgesehen ist, doch einmal einen Infix-Match benötigen, erweitern Sie einfach ihren regulären Ausdruck am Anfang mit .*, um eine beliebige vorangestellte Zeichenkette zu matchen.

Regulärer AusdruckMatchKein Match

/var

/var
/var/log

/usr/var

.*/var

/var
/usr/var
/var/log

/var$

/var

/var/log
/usr/var

Tipp: Sie können jede Suche am Anfang einer Zeichenkette mit ^ und jede Suche innerhalb mit .* einleiten, die Interpreter für reguläre Ausdrücke ignorieren redundante Symbole.

2.6. Sonderzeichen mit Backslash maskieren

Da der Punkt alles matcht, matcht er natürlich auch einen Punkt. Wenn Sie nun aber genau einen Punkt matchen wollen, so müssen Sie diesen mit einem \ (Backslash) maskieren (eingedeutscht: „escapen“). Das gilt analog auch für alle anderen Sonderzeichen. Dies sind: \ . * + ? { } ( ) [ ] | & ^ und $. Der \ Backslash wertet das nächste dieser Sonderzeichen als normales Zeichen:

Regulärer AusdruckMatchKein Match

example\.com

example.com

example\.com
example-com

Wie\?

Wie?

Wie\?
Wie

C:\\Programs

C:\Programs

C:Programs
C:\\Programs

Achtung Python: Da in Python der Backslash in der internen Zeichenkettendarstellung intern mit einem weiteren Backslash maskiert wird, müssen diese beiden Backslashes wiederum maskiert werden, was zu insgesamt vier Backslashes führt:

Regulärer AusdruckMatchKein Match

C:\\\\Programs

C:\Programs

C:Programs
C:\\Programs

2.7. Alternativen

Mit dem senkrechten Strich | können Sie Alternativen definieren, sprich eine ODER-Verküpfung verwenden: 1|2|3 matcht also 1, 2 oder 3. Wenn Sie die Alternativen inmitten eines Ausdrucks benötigen, gruppieren Sie diese innerhalb runder Klammern.

Regulärer AusdruckMatchKein Match

CPU load|Kernel|Memory

CPU load
Kernel

CPU utilization

01|02|1[1-5]

01
02
11 bis 15

05

2.8. Match-Gruppen

Match-Gruppen (englisch capture groups) erfüllen zwei Zwecke: Der erste ist — wie im letzten Beispiel gezeigt — die Gruppierung von Alternativen oder Teil-Matches, dabei sind auch verschachtelte Gruppierungen möglich. Zudem ist es zulässig, hinter runden Klammern die Wiederholungsoperatoren *, +, ? und {…​} zu verwenden. So passt der Ausdruck (/local)?/share sowohl auf /local/share als auch auf /share.

Der zweite Zweck ist das "Einfangen" gematchter Zeichengruppen in Variablen. In der Event Console (EC), Business Intelligence (BI), beim Massenumbenennen von Hosts und bei Piggyback-Zuordnungen besteht die Möglichkeit, den Textteil der dem regulären Ausdruck in der ersten Klammer entspricht, als \1 zu verwenden, den der zweiten Klammer entsprechenden als \2 usw. Das letzte Beispiel der Tabelle zeigt die Verwendung von Alternativen innerhalb einer Matchgruppe.

Regulärer AusdruckZu matchender TextGruppe 1Gruppe 2

([a-z]+)([123]+)

def231

def

231

server-(.*)\.local

server-lnx02.local

lnx02

server\.(intern|dmz|123)\.net

server.dmz.net

dmz

Folgende Abbildung zeigt eine solche Umbenennung die Umbenennung mehrerer Hosts. Alle Host-Namen, die auf den regulären Ausdruck server-(.*)\.local passen, werden durch \1.servers.local ersetzt. Dabei steht das \1 genau für den Text, der mit dem .* in der Klammer "eingefangen" wurde:

bulk renaming regex

Im konkreten Fall wird also server-lnx02.local in lnx02.servers.local umbenannt.

3. Tabelle der Sonderzeichen

Hier finden Sie zusammengefasst die Liste von allen oben erklärten Sonderzeichen und Funktionen der regulären Ausdrücke, die Checkmk verwendet:

.

Passt auf ein beliebiges Zeichen.

\

Wertet das nächste Sonderzeichen als normales Zeichen.

{5}

Das vorherige Zeichen muss genau fünfmal vorkommen.

{5,10}

Das vorherige Zeichen muss mindestens fünf- und höchstens zehnmal vorkommen.

*

Das vorherige Zeichen darf beliebig oft vorkommen (entspricht {0,}).

+

Das vorherige Zeichen darf beliebig oft, aber muss mindestens einmal vorkommen (entspricht {1,}).

?

Das vorherige Zeichen darf null- oder einmal vorkommen (entspricht {0,1}).

[abc]

Steht für genau eines der Zeichen a, b oder c.

[0-9]

Steht für genau eines der Zeichen 0, 1 …​ 9 (also eine Ziffer).

[0-9a-z_]

Steht für genau eine Ziffer, einen Kleinbuchstaben oder den Unterstrich.

[^"']

Steht für genau ein beliebiges Zeichen außer dem einfachen oder doppelten Anführungszeichen.

$

Matcht das Ende eines Textes.

^

Matcht den Anfang eines Textes.

A|B|C

Matcht auf A oder auf B oder auf C_.

(A)

Fasst den Unterausdruck A zu einer Match-Gruppe zusammen.

\t

Matcht einen Tabstop (Tabulator), dieses Zeichen kommt oft in Log-Dateien oder CSV-Tabellen vor

\s

Matcht alle Leerzeichen (ASCII kennt 5 verschiedene)

Folgende Zeichen müssen durch Backslash maskiert werden, wenn sie wörtlich verwendet werden sollen: \ . * + ? { } ( ) [ ] | & ^ $.

3.1. Unicode in Python 3

Insbesondere, wenn Eigennamen in Kommentaren oder beschreibenden Texten per Copy und Paste übernommen wurde und daher Unicode-Zeichen oder verschiedene Typen von Leerzeichen im Text auftreten, sind Pythons erweiterte Klassen sehr hilfreich:

\t

Matcht einen Tabstop (Tabulator), teils in Logdateien oder CSV-Tabellen

\s

Matcht alle Leerzeichen (Unicode kennt 25 verschiedene, ASCII 5)

\S

Invertierung von \s, matcht alle Zeichen, die keine Leerzeichen sind

\w

Matcht alle Zeichen, die Wortbestandteil sind, also Buchstaben, in Unicode aber auch Akzente, chinesische, arabische oder koreanische Glyphen, Achtung: Ziffern zählen hier zu den Wortbestandteilen!

\W

Invertierung von \w, matcht alles, was typischerweise kein Wortbestandteil ist (Leerzeichen, Satzzeichen, Emoticons, mathematische Sonderzeichen)

An Stellen, an denen Checkmk Unicode-Matching erlaubt, ist \w vor allem zur Suche nach ähnlich geschriebenen Worten in verschiedenen Sprachen hilfreich, beispielsweise Eigennamen, die mal mit und mal ohne Accent geschrieben werden.

Regular Expression

Match

Match

Kein Match

\w{1,3}ni\w{1,2}el

Schnitzel (Deutsch)

șnițel (Rumänisch)

šnicl (Kroatisch)
Schnit’el (mit Auslassungszeichen)

4. Test regulärer Ausdrücke

Die Logik regulärer Ausdrücke ist insbesondere bei verschachtelten Match-Gruppen oder der Frage in welcher Reihenfolge von welchem Ende des zu matchenden Strings ausgewertet wird, nicht immer einfach zu durchschauen. Besser als Trial and Error in Checkmk sind diese zwei Möglichkeiten zum Test regulärer Ausdrücke: Online-Dienste wie regex101.com bereiten Matches grafisch auf und erklären darüber die Reihenfolge der Auswertung in Echtzeit.

regexes testing

Die zweite Testmöglichkeit ist der Python-Prompt, den jede Python-Installation mitbringt. Unter Linux und auf dem Mac ist Python 3 in der Regel vorinstalliert. Gerade weil reguläre Ausdrücke am Python-Prompt exakt wie in Checkmk ausgewertet werden, gibt es auch bei komplexen Schachtelungen keine Abweichungen bei der Interpretation. Mit dem Test im Python-Interpreter sind Sie damit immer auf der sicheren Seite.

Nach dem Öffnen müssen Sie das Modul re importieren. Im Beispiel schalten wir zudem mit re.IGNORECASE die Unterscheidung zwischen Groß- und Kleinschreibung ab:

OMD[mysite]:~$ python3
Python 3.8.10 (default, Jun  2 2021, 10:49:15)
[GCC 9.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import re
>>> re.IGNORECASE
re.IGNORECASE

Um das Verhalten der regulären Ausdrücke von C nachzubilden, das auch in vielen Python-Komponenten genutzt wird, schränken Sie auf ASCII ein:

>>> re.ASCII
re.ASCII

Nun können Sie mit der Funktion re.match() direkt einen regulären Ausdruck gegen einen String matchen und die Matchgruppe ausgeben, group(0) steht hierbei für den gesamten Match, mit group(1) wird der Match ausgegeben, der zum ersten in einer runden Klammer gruppierten Unterausdruck passt.

>>> x = re.match('M[ae]{1}[iy]{1}e?r', 'Meier')
>>> x.group(0)
'Meier'
>>> x = re.match('M[ae]{1}[iy]{1}e?r', 'Mayr')
>>> x.group(0)
'Mayr'
>>> x = re.match('M[ae]{1}[iy]{1}e?r', 'Myers')
>>> x.group(0)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: no such group
>>> x = re.match('server-(.*)\.local', 'server-lnx23.local')
>>> x.group(0)
'server-lnx23.local'
>>> x.group(1)
'lnx23'

5. Weitere externe Dokumentation

Ken Thompson, einer der Erfinder von UNIX, hat schon in den 1960ern als erster reguläre Ausdrücke in der heutigen Form entwickelt — unter anderem im bis heute gebräuchlichen Unix-Befehl grep. Seitdem wurden zahlreiche Erweiterungen und Dialekte von regulären Ausdrücken geschaffen — darunter erweiterter Regexe, Perl-kompatible Regexe und auch eine sehr ähnlich Variante in Python.

Checkmk verwendet in den Filtern in Ansichten POSIX erweiterte reguläre Ausdrücke (extended REs). Diese werden im Monitoring-Kern in C mit der Regexfunktion der C-Bibliothek ausgewertet. Sie finden eine komplette Referenz dazu in der Linux-Manpage zu regex(7):

OMD[mysite]:~$ man 7 regex

REGEX(7)                   Linux Programmer's Manual                   REGEX(7)

NAME
       regex - POSIX.2 regular expressions

DESCRIPTION
       Regular  expressions  ("RE"s), as defined in POSIX.2, come in two forMFS:
       modern REs (roughly those of egrep; POSIX.2 calls these "extended"  REs)
       and  obsolete  REs (roughly those of *ed*(1); POSIX.2 "basic" REs).  Obso-
       lete REs mostly exist for backward compatibility in some  old  programs;

An allen anderen Stellen stehen darüber hinaus alle Möglichkeiten der regulären Ausdrücke von Python zur Verfügung. Dies betrifft unter anderem die Konfigurationsregeln, Event Console (EC) und Business Intelligence (BI). Die regulären Ausdrücke in Python sind eine Erweiterung der extended REs und sehr ähnlich zu denen aus Perl. Sie unterstützen z.B. den sogenannten negative Lookahead, einen nicht gierigen * Stern, oder ein Erzwingen der Unterscheidung von Groß-/Kleinschreibung. Die genauen Möglichkeiten dieser regulären Ausdrücke finden Sie in der Online-Hilfe von Python zum Modul re, oder ausführlicher in der Online-Dokumentation von Python:

OMD[mysite]:~$ pydoc3 re
Help on module re:

NAME
    re - Support for regular expressions (RE).

MODULE REFERENCE
    https://docs.python.org/3.8/library/re

    The following documentation is automatically generated from the Python
    source files.  It may be incomplete, incorrect or include features that
    are considered implementation detail and may vary between Python
    implementations.  When in doubt, consult the module reference at the
    location listed above.

DESCRIPTION
    This module provides regular expression matching operations similar to
    those found in Perl.  It supports both 8-bit and Unicode strings; both
    the pattern and the strings being processed can contain null bytes and
    characters outside the US ASCII range.

    Regular expressions can contain both special and ordinary characters.
    Most ordinary characters, like "A", "a", or "0", are the simplest
    regular expressions; they simply match themselves.  You can
    concatenate ordinary characters, so last matches the string 'last'.

Eine sehr ausführliche Erklärung zu regulären Ausdrücken finden Sie in der Wikipedia.

Auf dieser Seite