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.
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
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.
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
sed -i 's/[[:space:]]*$//' datei.ldif
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