silvesterlangen.de

Seite
Menü

reguläre Ausdrücke

Reguläre Ausdrücken ermöglichen dem User dem System seine Sicht auf die Daten zu geben und somit Anweisungen zu geben wie sie zu verarbeiten sind. So kann beispielsweise eine einfache Ausgabe des ls-Befehls besser verarbeitet werden. Hier mal ein kleines Beispiel:

desktop:~$ ls -lah
insgesamt 132K
drwx--x---+ 22 silvester silvester 4,0K  5. Okt 17:00 .
drwxr-xr-x.  4 root      root      4,0K  3. Okt 14:54 ..
-rw-------.  1 silvester silvester 2,2K  4. Okt 21:16 .bash_history
-rw-r--r--.  1 silvester silvester   18 20. Nov 2015  .bash_logout
-rw-r--r--.  1 silvester silvester  193 20. Nov 2015  .bash_profile
-rw-r--r--   1 silvester silvester  280  2. Okt 08:07 .bashrc
drwxr-xr-x.  2 silvester silvester 4,0K  2. Okt 08:42 Bilder
drwx--x---+  8 silvester silvester 4,0K  1. Okt 15:25 .cache
drwxr-xr-x. 14 silvester silvester 4,0K  5. Okt 17:00 .config
drwxr-xr-x.  2 silvester silvester 4,0K 30. Sep 20:05 Dokumente
drwxr-xr-x.  2 silvester silvester 4,0K  4. Okt 20:17 Downloads
-rw-------.  1 silvester silvester   16 30. Sep 20:05 .esd_auth

desktop:~$

 

Schaut man sich die Ausgabe genauer an, dann erkennt man Zeilen und Spalten. Man möchte quasi sagen, dass die Datei- und Verzeichnisnamen in der 9. Spalte stehen. Oder Benutzer und Gruppe stehen bspw. in der 3. und 4. Spalte. Es wäre doch wunderbar, könnte man dem System einfach sagen, dass man alles in eine Datei wegschreiben möchte oder eine Liste mit Benutzernamen.

Na, dann machen wir das doch mal. Das Programm, was uns die Dinge rausfiltern kann ist grep/egrep, aber auch Werkzeuge wie cut oder sed können mit regulären Ausdrücken umgehen. Wenn wir diese Programme durch Pipes miteinander verbinden, dann können wir die Fähigkeiten aller Programme in einem Zug durch nutzen. Das läuft dann wie folgt ab: ls -lah gibt das aktuelle Verzeichnis aus. Mittels Pipe wird die Ausgabe an das nächste Programm, tr, was überflüssige Leerzeichen rausfiltert. Dann wieder per Pipe an cut, übergeben. Cut gibt uns die Spalten aus, die wir haben wollen.

ls -lah | tr -s ' ' | cut -d ' ' -f 3,9

Erläuterungen: ls -lah gibt die oben gezeigte Ausgabe. tr -s ' ' filtert Zeichen heraus, die mehrfach aufeinander folgen wie das Leerzeichen  zwischen Spalte 1 und 2. Als nächstes filtert cut. Die Option -d ' ' zeigt cut wie die Spalten voneinander getrennt sind. Die Option -f 3,9 besagt, dass cut die Spalten 3 und 9 ausgeben soll.

SO EINFACH IST DAS!!!! :-D

 

Ein anderes Beispiel: Wir haben eine Konfigurationsdatei und an mehreren Stellen haben wir einen Wert stehen, der für dieses System nicht richtig ist. Wir wollen diese Konfigdatei ändern und damit wir nichts übersehen und später Probleme haben, nutzen wir sed. Sed ist ein StreamEditor und kann Daten einlesen, modifizieren und wieder wegschreiben. Also perfekt für unseren Zweck. Wir lesen zunächst die Konfigdatei mit cat ein, übergeben den Output an sed, der für uns das Substitute (ersetzen) vornnimmt und dann wird dessen Ausgabe in eine Datei umgeleitet und weggeschrieben.

cat blaservice.conf | sed 's/SUCHWORT/ERSATZWORT/g'
(s = substitute, g = global (also nicht nur am ersten Fundort ersetzen sondern alles).
 

Noch ein Beispiel: Wir haben eine Ausgabe und müssen daraus nach bestimmten Wörtern (strings) filtern. Als Ausgabe nutzen wir mal dmesg (Kernelmeldungen), weil es so schön viel Info erzeugt.

dmesg | grep 'sd[a-e]'

Wir erzeugen also die Datenflut, die dmesg ausgibt und pipen sie an grep weiter. Diesen wiederum weisen wir dann an nach einem String zu suchen, der mit sd beginnt und a, b, c, d oder e als nächsten Buchstaben enthält. Also genau gesagt sucht grep nun nach sda, sdb, sdc, sdd oder sde. Alles, was er findet gibt er uns dann aus.

 

uuuuuund noch eins, weil's so schön ist: Wir erzeugen wieder mit dmesg eine Datenflut auf der Console und pipen sie wieder an grep weiter. Mit grep lassen wir dann wieder suchen. Wir geben ein:

dmesg | grep '[0-9]*'

Nun wird grep uns alle Zahlen ausgaben und zwar nur Zahlen. Von einstellig bis x-stellig ist alles dabei. Egal wie lang die Zahl ist, grep gibt sie aus.

 

Noch was nützliches: Wir wollen aus der Ausgabe von ifconfig unsere IP für unsere Schnittstelle herausfiltern, weil wir die per Script dann weiterverarbeiten wollen für Konfigurationzwecke. Das geht wie folgt:

ifconfig  eno16777736 | egrep 'inet [0-9]{2,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}' | tr -s ' ' | cut -d ' ' -f3

Das geht auch noch etwas eleganter zu schreiben, aber für den Zweck reicht es aus. ;-)

 

Worte in versch. Schreibweisen finden

Sucht man ein alleinstehendes Wort, so muss man irgendwie ausdrücken können wo der Anfang und das Ende des Wortes sind. Das macht man in dem man das Wort zwischen zwei "b" setzt. Das schaut dann so aus:

bBlattb

Es wird nur noch das Wort Blatt gefunden. Nun kann es aber sein, dass das Wort mit großem ODER kleinem B geschrieben ist. Man muss also per regexp ausdrücken, dass ein Buchstabe in zwei Varianten vorkommen kann. Dazu nutzt man [Bb]. In der Eckigen Klammer drücke ich gerade also das Oder aus.

b[Bb]lattb

Nun kann es sein, dass der Autor des Textes der Rechtschreibung nicht ganz Herr ist und ich rechne damit, dass er Blat statt Blatt geschrieben hat. Auch das will ich abdecken. Ich brauche ein Zeichen, dass mir die Möglichkeit gibt auszudrücken, dass ein Buchstabe Null oder ein mal vorkommen darf. Das macht man mit dem ? (Fragezeichen). Das kommt hinter das Wort, welche 0 oder 1 x vorkommen darf. Meine Zeile sähe dann so aus:

b[Bb]lat?b

Nehmen wir mal ein anderes Wort. In Zeiten von Spam ist es gut, wenn man verschiedene Schreibweisen eines Wortes ausdrücken kann. So kann das Wort Viagra auch VIAgrA oder Vl4gr4 geschrieben werden. Auch das will ich berücksichtigen. Eine Zeile könnte also so ausschauen:

cat bla.txt | grep [Vv][iIl][aA4][gG][rR][aA4]

Natürlich gehen nicht nur Zahlen und Buchstaben. Auch Zeichen können genutzt werden. So könnte ein @ für ein A stehen oder ein ! für ein i oder eine 1. Das Konstrukt kann man jetzt ewig weiterspinnen.

 

alphanummerische Zeichenkette filtern

Hat man das Problem, dass man eine alphanummerische Zeichenkette aus einer Zeile holen muss, so lässt sich dafür folgendes verwenden:

cat bla.log | egrep -o [A-Za-z0-9.]{3,7}

Es wird in den eckigen Klammern definiert welche Zeichen möglich sind. Der Punkt dahinter gesagt, dass es ein beliebiges Zeichen sein darf. In den geschweiften Klammern legt man fest wie oft das vorkommen darf. Die obige Zeile sucht also eine Zeichenkette, die Zahlen und Groß- sowie Kleinbuchstaben berücksichtig und diese Zeichenkette mindestens 3, aber jedoch nicht mehr als 7 Zeichen haben darf

 

Oder ein reales Beispiel:
Dafür hält jetzt mal die /etc/postfix/master.cf her. In ihr wird in der Zeile
"#submission inet n       -       -       -       -       smtpd" das Kommentarzeichen entfernt. Das ist nicht so schwer. Wenn überhaupt, dann ist nur der Teil schwieriger SED mittels RegEx verständlich zu machen was genau gemeint ist.
sed -i 's/^#submission inet.*$/submission inet n       -       -       -       -       smtpd/' /etc/postfix/master.cf
 
Mit #submisstion inet.*$ läuft das folgendermaßen:
Das ^ besagt, dass der Anfang der Zeile gemeint ist. Dann, was dort stehen soll. Da wir nicht die ganze Zeile jedes mal aufzeigen wollen sondern nur so viel, dass eine eindeutige Erkennung möglich ist, schreiben wir nur #submission inet hinter das ^ und das reicht schon aus, um die Zeile eindeutig zu identifizieren. Mit dem . sagen wir, dass dahinter noch ein Zeichen folgt. Das * besagt, dass das Zeichen vorher (also der . der für ein beliebiges Zeichen steht) beliebig oft vorkommen kann. Somit ist jede mögliche Länge der zeile abgedeckt. Mit $ sagen wir, dass das das Ende der Zeile ist. Das war es auch schon.
 
Dann geht es nur noch mit dem Ersatzstring weiter.

 

Eine schöne List welche Möglichkeiten regex (regular expressions) bietet:

Selektieren:

.       steht für ein beliebiges Zeichen
^, $    ^Zeilenanfang, $Zeilenende
<, >    < Wortanfang, >Wortende
[...]   steht für ein Zeichen aus der angegebenen Menge
[^..]   Negation, wenn man Zeichen ausschließen will.
(...)   definiert einen RegEx-Bereich, der bspw. wiederholt werden kann

 

Multiplikatoren:

*       darf beliebig oft vorkommen
+       darf beliebig oft vorkommen, aber mind. 1 x
?       darf kein oder ein mal vorkommen
{n,m}   mind. "m" mal aber max "n" mal vorkommen
{n}     muss genau n mal vorkommen
{n,}    muss mind. n mal vorkommen.
 
Eines noch... Wenn man in der Zeile (Suchstring oder Ersatzstring) Zeichen wie *, /, . oder & hat, dann muss ein Escape (ein Backslash) voran gesetzt werden.
Beispiel:
sed -i 's/#myorigin = \/etc\/mailname/myorigin = \/etc\/mailname/' /etc/postfix/main.cf
 
Die "Escapes" sind hier rot eingezeichnet. Da / in den RegEx eine Bedeutung hat, muss es mit \ neutralisiert werden, damit es als Teil des Strings behandelt wird.
 
Zur besseren Lesbarkeit:
sed -i 's/#myorigin = \/etc\/mailname/myorigin = \/etc\/mailname/' /etc/postfix/main.cf
 
Mehrzeilig hinter einem String einfügen:
In diesem Beispiel setze ich hinter dem String <IfModule mod_php5.*$ mehrere Zeilen die für die Apache2 Konfiguration gebraucht werden. Den Zeilenumbruch mache ich mit \n. Ich lass hier das "s" weg (gemeint ist das hier: sed -i 's///'), weil ich nicht ersetzen sondern anhängen möchte.
 
sed -i -e '/<IfModule mod_php5.*$/a\' -e '    AddType application/x-httpd-php .php\n    php_flag magic_quotes_gpc Off\n    php_flag track_vars On\n    php_admin_flag allow_url_fopen Off\n    php_value include_path .\n    php_admin_value upload_tmp_dir /var/lib/squirrelmail/tmp\n    php_admin_value open_basedir /usr/share/squirrelmail:/etc/squirrelmail:/var/lib/squirrelmail:/etc/hostname:/etc/mailname' ./apache.conf
 
Jedes zweite Zeichen einen Doppelpunkt setzen:
Es kann schon mal nützlich sein einer Zeichenkette alle X Zeichen ein zusätzliches Zeichen hinzuzufügen. In meinem Fall war es eine große Liste mit MAC-Adressen.
 MAC=$(echo "54DEADBEEF15" | sed "s/.\{2\}/&:/g")
Die Ausgabe dann mit echo...
echo ${MAC%?}

Um eine Datei zeilenweise auszulesen kann man folgende Schleife verwenden:

for eintrag in $(cat /home/maclist.txt)
  do
    MAC=$(echo $eintrag | sed "s/.\{2\}/&:/g")
    echo ${MAC%?} >> neue_macliste.txt
done;

 

Bestimmte Teile aus einem String rausziehen.
Falls man mal aus einem String bestimmte Teile herausziehen muss, bietet sich awk an. In diesem Beispiel sind es FQDN von Beispielservern woraus ich den Hostnamen und den Standort brauche und speichere das in eine Datei.

echo "ve9328.blue.koeln-datacenter.superserver.com" | awk -F "." ' { print $1 ";" $3 } ' 

Mit der Option -F teile ich awk mit, dass der Punkt der Separator ist. Nun kann ich mit einem print sagen welchen Teil ich haben möchte. In diesem Fall sind es 1 und 3.

 

Per Script Teile aus dem String holen

ref=$(cat Datei.txt)
for value in $ref
  do
        VariableEins=$(echo $value | cut -d '-' -f1)
        VariableEins2=$(echo $value | cut -d '-' -f2)
echo $VariableEins";"$VariableEins2
done

 
Leerzeichen am Ende jeder Zeile löschen
sed -i 's/[[:space:]]*$//' datei.ldif
 
 
In sed ein einzelnes Quote ( ' ) escapen
Das ist nicht so einfach und man erreicht es so wie folgt. Das Rote ist das, was zu escapen gilt:
 ' " ' " '
Ausgesprochen also: Single-Quote, Double-Quote, Single-Quote, Double-Quote, Single-Quote
 

 

Bash-Umleitungen

stdout -> Datei umleiten

program > Datei.txt

stderr -> Datei umleiten

program 2> Datei.txt

stdout UND stderr -> Datei umleiten

program &> Datei.txt

stdout -> Datei umleiten UND stderr -> Datei umleiten

program > Datei_stdout.txt 2> Datei_stderr.txt

stdout -> stderr

program 1>&2

stderr -> stdout

program 2>&1

« vorige Seite Seitenanfang nächste Seite »
Seite
Menü
Earned Certificates:
LPIC-1 LPIC-1 LPIC-1
Powered by CMSimple | Template by CMSimple | Login