103.7 Lektion 2
Zertifikat: |
LPIC-1 |
---|---|
Version: |
5.0 |
Thema: |
103 GNU- und Unix-Befehle |
Lernziel: |
103.7 Textdateien mit regulären Ausdrücken durchsuchen |
Lernziel: |
2 von 2 |
Einführung
Das Streaming von Daten durch eine Kette von Pipelinebefehlen ermöglicht die Anwendung von zusammengesetzten Filtern auf der Grundlage regulärer Ausdrücke. Reguläre Ausdrücke sind eine wichtige Technik, die nicht nur in der Systemadministration, sondern auch im Data-Mining und verwandten Bereichen eingesetzt wird. Zwei Befehle eignen sich besonders für die Manipulation von Dateien und Textdaten mit regulären Ausdrücken: grep
und sed
. grep
ist ein Musterfinder und sed
ein Streameditor. Sie sind für sich allein nützlich, aber gerade in Zusammenarbeit mit anderen Prozessen stechen sie besonders hervor.
Der Musterfinder: grep
Eine der häufigsten Anwendungen von grep
ist die Erleichterung der Inspektion größerer Dateien, wobei reguläre Ausdrücke als Filter auf jede Zeile angewendet werden. Er kann verwendet werden, um nur die Zeilen anzuzeigen, die mit einem bestimmten Begriff beginnen. Zum Beispiel kann grep
verwendet werden, um eine Konfigurationsdatei für Kernelmodule zu untersuchen, wobei nur Optionszeilen aufgelistet werden:
$ grep '^options' /etc/modprobe.d/alsa-base.conf options snd-pcsp index=-2 options snd-usb-audio index=-2 options bt87x index=-2 options cx88_alsa index=-2 options snd-atiixp-modem index=-2 options snd-intel8x0m index=-2 options snd-via82xx-modem index=-2
Das Pipezeichen |
kann verwendet werden, um die Ausgabe eines Befehls direkt auf die Eingabe von grep
umzuleiten. Das folgende Beispiel verwendet einen Klammerausdruck, um Zeilen aus der Ausgabe von fdisk -l
auszuwählen, beginnend mit Disk /dev/sda
oder Disk /dev/sdb
:
# fdisk -l | grep '^Disk /dev/sd[ab]' Disk /dev/sda: 320.1 GB, 320072933376 bytes, 625142448 sectors Disk /dev/sdb: 7998 MB, 7998537728 bytes, 15622144 sectors
Die bloße Auswahl von Zeilen mit Übereinstimmungen ist möglicherweise für eine bestimmte Aufgabe nicht geeignet und erfordert Anpassungen des Verhaltens von grep
durch seine Optionen. Zum Beispiel weist die Option -c
oder --count
grep
an, um darzustellen, wie viele Zeilen eine Übereinstimmungen enthalten:
# fdisk -l | grep '^Disk /dev/sd[ab]' -c 2
Die Option kann vor oder nach dem regulären Ausdruck stehen. Andere wichtige Optionen von grep
sind:
-c
oder--count
-
Anstatt die Suchergebnisse anzuzeigen, wird nur die Gesamtzahl angezeigen, wie oft eine Übereinstimmung in einer bestimmten Datei auftritt.
-i
oder--ignore-case
-
Beachten bei der Suche nicht die Groß-/Kleinschreibung.
-f FILE
oder--file=FILE
-
Gibt die Datei an, welche den zu verwendenden regulären Ausdruck enthält.
-n
oder--line-number
-
Zeigt die Nummer der übereinstimmenden Zeile an.
-v
oder--invert-match
-
Wählt jede Zeile aus, mit Ausnahme der Zeilen, die eine Übereinstimmungen enthalten.
-H
oder--with-filename
-
Veranlasst die Ausgabe des Namens der Datei, welche die übereinstimmende Zeile enthält.
-z
oder--null-data
-
Statt
grep
Ein- und Ausgabedatenströme als getrennte Zeilen zu behandeln (standardmäßig per Zeilenumbruch), wird die Ein- oder Ausgabe als eine Folge von Zeilen angenommen. Wenn die Ausgabe des Befehlsfind
unter Verwendung seiner Option-print0
mit dem Befehlgrep
kombiniert wird, sollte die Option-z
oder--null-data
verwendet werden, um den Datenstrom auf die gleiche Weise zu verarbeiten.
Obwohl standardmäßig aktiviert, wenn mehrere Dateipfade als Eingabe angegeben werden, ist die Option -H
für einzelne Dateien nicht aktiviert. Das kann in besonderen Situationen nachteilhaft sein, wie z.B. wenn grep
direkt von find
aufgerufen wird:
$ find /usr/share/doc -type f -exec grep -i '3d modeling' "{}" \; | cut -c -100 artistic aspects of 3D modeling. Thus this might be the application you are This major approach of 3D modeling has not been supported oce is a C++ 3D modeling library. It can be used to develop CAD/CAM softwares, for instance [FreeCad
In diesem Beispiel listet find
jede Datei unter /usr/share/doc
auf und übergibt sie dann an grep
, das wiederum eine nicht-sensitive Suche nach 3D modeling
innerhalb der Datei durchführt. Die Pipe zu cut
ist nur dazu da, die Ausgabelänge auf 100 Spalten zu begrenzen. Beachten Sie jedoch, dass es keine Möglichkeit gibt, herauszufinden, aus welcher Datei die Zeilen stammen. Dieses Problem wird durch Hinzufügen von -H
zu grep
behoben:
$ find /usr/share/doc -type f -exec grep -i -H '3d modeling' "{}" \; | cut -c -100 /usr/share/doc/openscad/README.md:artistic aspects of 3D modeling. Thus this might be the applicatio /usr/share/doc/opencsg/doc/publications.html:This major approach of 3D modeling has not been support
Jetzt ist es möglich, die Dateien zu identifizieren, in denen eine Übereinstimmung gefunden wurde. Um die Auflistung noch aussagekräftiger zu gestalten, können übereinstimmende Zeilen mit führenden und abschließenden Zeilen versehen werden:
$ find /usr/share/doc -type f -exec grep -i -H -1 '3d modeling' "{}" \; | cut -c -100 /usr/share/doc/openscad/README.md-application Blender), OpenSCAD focuses on the CAD aspects rather t /usr/share/doc/openscad/README.md:artistic aspects of 3D modeling. Thus this might be the applicatio /usr/share/doc/openscad/README.md-looking for when you are planning to create 3D models of machine p /usr/share/doc/opencsg/doc/publications.html-3D graphics library for Constructive Solid Geometry (CS /usr/share/doc/opencsg/doc/publications.html:This major approach of 3D modeling has not been support /usr/share/doc/opencsg/doc/publications.html-by real-time computer graphics until recently.
Die Option -1
weist grep
an, eine Zeile davor und eine Zeile danach einzufügen, wenn es eine Zeile mit einer Übereinstimmung findet. Diese zusätzlichen Zeilen werden Kontextzeilen genannt und in der Ausgabe durch ein Minuszeichen hinter dem Dateinamen gekennzeichnet. Das gleiche Ergebnis kann mit -C 1
oder --context=1
erzielt werden, und es können auch andere Kontextzeilenmengen angegeben werden.
Es gibt zwei ergänzende Programme zu grep: egrep
und fgrep
. Das Programm egrep
ist äquivalent zum Befehl grep -E
, der neben den einfachen regulären Ausdrücken weitere Funktionen beinhaltet. Zum Beispiel ist es mit egrep
möglich, Funktionen erweiterter regulärer Ausdrücke, wie Verzweigungen, zu verwenden:
$ find /usr/share/doc -type f -exec egrep -i -H -1 '3d (modeling|printing)' "{}" \; | cut -c -100 /usr/share/doc/openscad/README.md-application Blender), OpenSCAD focuses on the CAD aspects rather t /usr/share/doc/openscad/README.md:artistic aspects of 3D modeling. Thus this might be the applicatio /usr/share/doc/openscad/README.md-looking for when you are planning to create 3D models of machine p /usr/share/doc/openscad/RELEASE_NOTES.md-* Support for using 3D-Mouse / Joystick / Gamepad input dev /usr/share/doc/openscad/RELEASE_NOTES.md:* 3D Printing support: Purchase from a print service partne /usr/share/doc/openscad/RELEASE_NOTES.md-* New export file formats: SVG, 3MF, AMF /usr/share/doc/opencsg/doc/publications.html-3D graphics library for Constructive Solid Geometry (CS /usr/share/doc/opencsg/doc/publications.html:This major approach of 3D modeling has not been support /usr/share/doc/opencsg/doc/publications.html-by real-time computer graphics until recently.
In diesem Beispiel wird entweder 3D modeling
oder 3D printing
mit dem Ausdruck übereinstimmen, Groß-/Kleinschreibung wird nicht berücksichtigt. Um nur die Teile eines Textstroms anzuzeigen, die mit dem von egrep
verwendeten Ausdruck übereinstimmen, verwenden Sie die Option -o
.
Das Programm fgrep
ist äquivalent zu grep -F
, was bedeutet das es keine regulären Ausdrücke parst. Es ist nützlich bei einfachen Suchvorgängen, bei denen das Ziel darin besteht, einen wörtlichen Ausdruck zu finden. Daher werden Sonderzeichen wie das Dollarzeichen und der Punkt in einem regulären Ausdruck wörtlich und nicht nach ihrer Bedeutung interpretiert.
Der Streameditor: sed
Der Zweck des Programms sed
besteht darin, textbasierte Daten auf nicht-interaktive Weise zu modifizieren. Das bedeutet, dass die gesamte Bearbeitung durch vordefinierte Anweisungen erfolgt und nicht durch willkürliches Eintippen direkt in einen auf dem Bildschirm angezeigten Text. In moderner Hinsicht kann sed
als ein Vorlagenparser verstanden werden: einem Text als Eingabe übergeben, platziert es benutzerdefinierte Inhalte an vordefinierten Positionen oder an Stellen, welche eine Übereinstimmung mit einem regulären Ausdruck aufweisen.
Sed eignet sich, wie der Name schon sagt, gut für Text, der durch Pipelines geleitet wird. Seine grundlegende Syntax lautet sed -f SCRIPT
, wenn Editieranweisungen in der Datei SCRIPT
gespeichert sind, oder sed -e COMMANDS
, um COMMANDS
direkt von der Kommandozeile auszuführen. Wenn weder -f
noch -e
verwendet werden, benutzt sed
den ersten Nichtoptionsparameter als Skriptdatei. Es ist auch möglich, eine Datei als Eingabe zu verwenden, indem man einfach den Pfad als Argument an sed
übergibt.
Anweisungen von sed
bestehen aus einem einzigen Zeichen, dem möglicherweise eine Adresse vorangestellt ist oder auf das eine oder mehrere Optionen folgen, und werden auf jede Zeile einzeln angewendet. Adressen können eine einzelne Zeilennummer, ein regulärer Ausdruck oder ein Bereich von Zeilen sein. Zum Beispiel kann die erste Zeile eines Textstroms mit 1d
gelöscht werden, wobei 1
die Zeile angibt, auf die der Löschbefehl d
angewendet wird. Um die Verwendung von sed
zu verdeutlichen, verwenden wir die Ausgabe des Befehls factor `seq 12`
, der die Primfaktoren für die Zahlen 1 bis 12 zurückgibt:
$ factor `seq 12` 1: 2: 2 3: 3 4: 2 2 5: 5 6: 2 3 7: 7 8: 2 2 2 9: 3 3 10: 2 5 11: 11 12: 2 2 3
Das Löschen der ersten Zeile mit sed
wird durch 1d
erreicht:
$ factor `seq 12` | sed 1d 2: 2 3: 3 4: 2 2 5: 5 6: 2 3 7: 7 8: 2 2 2 9: 3 3 10: 2 5 11: 11 12: 2 2 3
Ein Zeilenbereich kann mit einem Trennkomma angegeben werden:
$ factor `seq 12` | sed 1,7d 8: 2 2 2 9: 3 3 10: 2 5 11: 11 12: 2 2 3
In der gleichen Ausführung kann mehr als eine Anweisung, getrennt durch Semikolons, verwendet werden. In diesem Fall ist es jedoch wichtig, diese mit Anführungszeichen zu umschließen, damit das Semikolon nicht von der Shell interpretiert wird:
$ factor `seq 12` | sed "1,7d;11d" 8: 2 2 2 9: 3 3 10: 2 5 12: 2 2 3
In diesem Beispiel wurden zwei Löschbefehle ausgeführt, zuerst auf Zeilen von 1 bis 7 und dann auf Zeile 11. Eine Adresse kann auch ein regulärer Ausdruck sein, so dass nur Zeilen mit einer Übereinstimmung von der Anweisung betroffen sind:
$ factor `seq 12` | sed "1d;/:.*2.*/d" 3: 3 5: 5 7: 7 9: 3 3 11: 11
Der reguläre Ausdruck :.*2.*
stimmt mit jedem Vorkommen der Zahl 2 irgendwo nach einem Doppelpunkt überein, was zur Löschung von Zeilen führt, welche die Zahlen 2 als Faktor enthalten. Mit sed
wird alles, was zwischen Schrägstrichen (/
) steht, als regulärer Ausdruck betrachtet, und standardmäßig werden alle einfachen RE unterstützt. Zum Beispiel zeigt sed -e "/^#/d" /etc/services
den Inhalt der Datei /etc/services
ohne die Zeilen, die mit #
(Kommentarzeilen) beginnen.
Der Löschbefehl d
ist nur einer der vielen Editierbefehle, die von sed
zur Verfügung gestellt werden. Anstatt eine Zeile zu löschen, kann sed
sie durch einen bestimmten Text ersetzen:
$ factor `seq 12` | sed "1d;/:.*2.*/c REMOVED" REMOVED 3: 3 REMOVED 5: 5 REMOVED 7: 7 REMOVED 9: 3 3 REMOVED 11: 11 REMOVED
Die Anweisung c REMOVED
ersetzt einfach eine Zeile durch den Text REMOVED
. Im Fall des Beispiels ist jede Zeile mit einer Teilzeichenkette, die dem regulären Ausdruck :.*2.*
entspricht, von der Anweisung c REMOVED
betroffen. Die Anweisung a TEXT
kopiert den mit TEXT
bezeichneten Text in eine neue Zeile nach der Zeile mit einer Übereinstimmung. Die Anweisung r FILE
tut dasselbe, kopiert aber den Inhalt der mit FILE
bezeichneten Datei. Die Anweisung w
bewirkt das Gegenteil von r
, d.h. die Zeile wird an die angegebene Datei angehängt.
Die bei weitem am häufigsten verwendete Anweisung an sed
ist s/FIND/REPLACE/
, die verwendet wird, um eine Übereinstimmung mit dem regulären Ausdruck FIND
durch den Text REPLACE
zu ersetzen. Beispielsweise ersetzt die Anweisung s/hda/sda/
eine Teilzeichenkette, die dem wörtlichem RE hda
entspricht, durch sda
. Nur die erste Übereinstimmung, die in der Zeile gefunden wird, wird ersetzt, es sei denn, die Flagge g
(global) wird nach der Anweisung gesetzt, wie in s/hda/sda/g
.
Ein realistisches Anwendungsbeispiel wird helfen, die Merkmale von sed
zu veranschaulichen. Nehmen wir an, eine medizinische Klinik möchte Textnachrichten an ihre Kunden senden, um diese an ihre geplanten Termine für den nächsten Tag zu erinnern. Ein typisches Implementierungsszenario stützt sich auf einen professionellen Sofortnachrichtendienst, der eine API für den Zugriff auf das für die Zustellung der Nachrichten zuständige System bereitstellt. Diese Nachrichten stammen in der Regel aus demselben System, in dem die Anwendung läuft, welche die Termine des Kunden steuert, ausgelöst durch eine bestimmte Tageszeit oder ein anderes Ereignis. In dieser hypothetischen Situation könnte die Anwendung eine Datei namens appointments.csv
erzeugen, die tabellarische Daten mit allen Terminen für den nächsten Tag enthält, die dann von sed
verwendet werden, um die Textnachrichten aus einer Vorlagendatei namens template.txt
zu rendern. CSV-Dateien sind eine Standardmethode, um Daten aus Datenbankabfragen zu exportieren, daher könnten Beispieltermine wie folgt vorliegen:
$ cat appointments.csv "NAME","TIME","PHONE" "Carol","11am","55557777" "Dave","2pm","33334444"
Die erste Zeile enthält die Beschriftungen für jede Spalte, die verwendet werden, um die Tags innerhalb der Beispielvorlagendatei abzugleichen:
$ cat template.txt Hey <NAME>, don't forget your appointment tomorrow at <TIME>.
Die Kleiner-als- <
und Größer-als- >
Zeichen wurden um Marker herum angebracht, um diese als Tags zu identifizieren. Das folgende Bash-Skript parst alle Termine in der Warteschlange und verwendet template.txt
als Nachrichtenvorlage:
#! /bin/bash TEMPLATE=`cat template.txt` TAGS=(`sed -ne '1s/^"//;1s/","/\n/g;1s/"$//p' appointments.csv`) mapfile -t -s 1 ROWS < appointments.csv for (( r = 0; r < ${#ROWS[*]}; r++ )) do MSG=$TEMPLATE VALS=(`sed -e 's/^"//;s/","/\n/g;s/"$//' <<<${ROWS[$r]}`) for (( c = 0; c < ${#TAGS[*]}; c++ )) do MSG=`sed -e "s/<${TAGS[$c]}>/${VALS[$c]}/g" <<<"$MSG"` done echo curl --data message=\"$MSG\" --data phone=\"${VALS[2]}\" https://mysmsprovider/api done
Ein tatsächliches Produktionsskript würde auch die Authentifizierung, Fehlerprüfung und Protokollierung handhaben, aber das Beispiel verfügt zunächst nur über grundlegende Funktionen. Die ersten Anweisungen, die von sed
ausgeführt werden, werden nur auf die erste Zeile angewendet — die Adresse 1
in 1s/^"//;1s/","/\n/g;1s/"$//p
— um die führenden und abschließenden Anführungszeichen zu entfernen — 1s/^"//
und 1s/"$//
— und um Feldtrennzeichen durch ein Zeilenumbruchszeichen zu ersetzen: 1s/","/\n/g
. Nur die erste Zeile wird für das Laden von Spaltennamen benötigt, so dass nicht übereinstimmende Zeilen durch die Option -n
unterdrückt werden, was erfordert, dass das Flag p
nach dem letzten sed
-Kommando gesetzt wird, um die übereinstimmende Zeile auszugeben. Die Tags werden dann in der Variablen TAGS
als ein Bash-Array gespeichert. Eine weitere Bash-Array-Variable wird durch den Befehl mapfile
erzeugt, um die Zeilen, die die Termine enthalten, in der Array-Variablen ROWS
zu speichern.
Eine for
-Schleife wird verwendet, um jede Terminzeile, die in ROWS
gefunden wird, zu verarbeiten. Dann werden Anführungszeichen und Trennzeichen im Termin — der Termin steht in der Variable ${ROWS[$r]}
, die als Here String verwendet wird — durch sed
ersetzt, ähnlich wie die Befehle, die zum Laden der Tags verwendet werden. Die getrennten Werte für den Termin werden dann in der Array-Variablen VALS
gespeichert, wobei die Array-Indizes 0, 1 und 2 den Werten für NAME
, TIME
und PHONE
entsprechen.
Schließlich läuft eine verschachtelte for
-Schleife durch das TAGS
-Array und ersetzt jedes in der Vorlage gefundene Tag durch seinen entsprechenden Wert in VALS
. Die Variable MSG
enthält eine Kopie der gerenderten Vorlage, die bei jedem Schleifendurchlauf durch TAGS
mittels dem Ersetzungsbefehl s/<${TAGS[$c]}>/${VALS[$c]}/g
aktualisiert wird.
Das Ergebnis ist eine gerenderte Botschaft: "Hey Carol, don’t forget your appointment tomorrow at 11am."
Die gerenderte Nachricht kann dann als Parameter durch eine HTTP-Anforderung mit curl
, als E-Mail-Nachricht oder eine ähnliche Methode versendet werden.
Kombination von grep und sed
Die Befehle grep
und sed
können zusammen verwendet werden, wenn komplexeres Text Mining erforderlich ist. Als Systemadministrator möchte man z. B. alle Anmeldeversuche an einem Server untersuchen. Die Datei /var/log/wtmp
zeichnet alle An- und Abmeldungen auf, während die Datei /var/log/btmp
die fehlgeschlagenen Anmeldeversuche aufzeichnet. Diese werden im Binärformat abgelegt, welches mit den Befehlen last
bzw. lastb
gelesen werden kann.
Die Ausgabe von lastb
zeigt nicht nur den beim fehlgeschlagenen Anmeldeversuch verwendeten Benutzernamen, sondern auch dessen IP-Adresse:
# lastb -d -a -n 10 --time-format notime user ssh:notty (00:00) 81.161.63.251 nrostagn ssh:notty (00:00) vmd60532.contaboserver.net pi ssh:notty (00:00) 132.red-88-20-39.staticip.rima-tde.net pi ssh:notty (00:00) 132.red-88-20-39.staticip.rima-tde.net pi ssh:notty (00:00) 46.6.11.56 pi ssh:notty (00:00) 46.6.11.56 nps ssh:notty (00:00) vmd60532.contaboserver.net narmadan ssh:notty (00:00) vmd60532.contaboserver.net nominati ssh:notty (00:00) vmd60532.contaboserver.net nominati ssh:notty (00:00) vmd60532.contaboserver.net
Die Option -d
übersetzt die IP-Nummer in den entsprechenden Hostnamen. Der Hostname kann Hinweise auf den ISP oder den Hostingdienst liefern, der für diese fehlerhaften Anmeldeversuche verwendet wurde. Die Option -a
setzt den Hostnamen in die letzte Spalte, was die noch auszuführende Filterung erleichtert. Die Option --time-format notime
unterdrückt die Zeit, zu der der Anmeldeversuch stattfand. Der Befehl lastb
kann einige Zeit in Anspruch nehmen, wenn es zu viele fehlerhafte Anmeldeversuche gab, daher wurde die Ausgabe mit der Option -n 10
auf zehn Einträge begrenzt.
Nicht allen Remote-IPs ist ein Hostname zugeordnet, so dass Reverse-DNS nicht auf diese anwendbar ist und verworfen werden können. Obwohl man einen regulären Ausdruck benutzen könnte, der mit dem erwarteten Format für einen Hostnamen am Ende der Zeile übereinstimmt, ist es wahrscheinlich einfacher, einen regulären Ausdruck zu schreiben, der entweder mit einem Buchstaben aus dem Alphabet oder mit einer einzelnen Ziffer am Ende der Zeile übereinstimmt. Das folgende Beispiel zeigt, wie der Befehl grep
die Ausgabe an seiner Standardeingabe entgegen nimmt und die Zeilen ohne Hostnamen entfernt:
# lastb -d -a --time-format notime | grep -v '[0-9]$' | head -n 10 nvidia ssh:notty (00:00) vmd60532.contaboserver.net n_tonson ssh:notty (00:00) vmd60532.contaboserver.net nrostagn ssh:notty (00:00) vmd60532.contaboserver.net pi ssh:notty (00:00) 132.red-88-20-39.staticip.rima-tde.net pi ssh:notty (00:00) 132.red-88-20-39.staticip.rima-tde.net nps ssh:notty (00:00) vmd60532.contaboserver.net narmadan ssh:notty (00:00) vmd60532.contaboserver.net nominati ssh:notty (00:00) vmd60532.contaboserver.net nominati ssh:notty (00:00) vmd60532.contaboserver.net nominati ssh:notty (00:00) vmd60532.contaboserver.net
Der Befehl grep
mit der Option -v
zeigt nur die Zeilen an, die nicht mit dem angegebenen regulären Ausdruck übereinstimmen. Ein regulärer Ausdruck, der auf eine beliebige Zeile passt, die mit einer Zahl endet (d. h. [0-9]$
), erfasst nur die Einträge ohne einen Hostnamen. Daher zeigt grep -v '[0-9]$'
nur die Zeilen an, die mit einem Hostnamen enden.
Die Ausgabe kann noch weiter gefiltert werden, indem nur der Domainname behalten und die anderen Teile aus jeder Zeile entfernt werden. Der Befehl sed
kann dies mit einem Ersetzungsbefehl tun, um die gesamte Zeile durch einen Rückverweis auf den darin enthaltenen Domänennamen zu ersetzen:
# lastb -d -a --time-format notime | grep -v '[0-9]$' | sed -e 's/.* \(.*\)$/\1/' | head -n 10 vmd60532.contaboserver.net vmd60532.contaboserver.net vmd60532.contaboserver.net 132.red-88-20-39.staticip.rima-tde.net 132.red-88-20-39.staticip.rima-tde.net vmd60532.contaboserver.net vmd60532.contaboserver.net vmd60532.contaboserver.net vmd60532.contaboserver.net vmd60532.contaboserver.net
Die geschützte Klammer in .* \(.*\)$
weist sed
an, sich diesen Teil der Zeile zu merken, d. h. den Teil zwischen dem letzten Leerzeichen und dem Ende der Zeile. Im Beispiel wird dieser Teil mit \1
referenziert und zum Ersetzen der gesamten Zeile verwendet.
Es ist klar, dass die meisten entfernten Hosts versuchen, sich mehr als einmal anzumelden, daher wiederholt sich derselbe Domänenname. Um die wiederholten Einträge zu unterdrücken, muss zunächst sortiert werden (mit dem Befehl sort
) und dann an den Befehl uniq
übergeben werden:
# lastb -d -a --time-format notime | grep -v '[0-9]$' | sed -e 's/.* \(.*\)$/\1/' | sort | uniq | head -n 10 116-25-254-113-on-nets.com 132.red-88-20-39.staticip.rima-tde.net 145-40-33-205.power-speed.at tor.laquadrature.net tor.momx.site ua-83-226-233-154.bbcust.telenor.se vmd38161.contaboserver.net vmd60532.contaboserver.net vmi488063.contaboserver.net vmi515749.contaboserver.net
Dies zeigt, wie verschiedene Befehle kombiniert werden können, um das gewünschte Ergebnis zu erzielen. Die Hostnamenliste kann dann verwendet werden, um blockierende Firewall-Regeln zu schreiben oder andere Maßnahmen zu ergreifen, um die Sicherheit des Servers zu verbessern.
Geführte Übungen
-
Der Befehl
last
zeigt eine Liste der zuletzt eingeloggten Benutzer, einschließlich ihrer Herkunfts-IPs. Wie würde der Befehlegrep
verwendet werden, um die Ausgabe vonlast
so zu filtern, das nur die genannte IPv4-Adresse anzeigt wird und alle zusätzlichen Informationen in der entsprechenden Zeile verwirft? -
Welche Option sollte an
grep
übergeben werden, um die Ausgabe, die durch den mit der Option-print0
ausgeführten Befehlfind
erzeugt wird, korrekt zu filtern? -
Der Befehl
uptime -s
zeigt das letzte Datum an, an dem das System eingeschaltet wurde, wie in2019-08-05 20:13:22
. Was wird das Ergebnis des Befehlsuptime -s | sed -e 's/(.*) (.*)/\1/'
sein? -
Welche Option sollte man
grep
geben, damit es übereinstimmende Zeilen zählt, anstatt diese anzuzeigen?
Offene Übungen
-
Die Grundstruktur einer HTML-Datei beginnt mit den Elementen
html
,head
undbody
, zum Beispiel:<html> <head> <title>News Site</title> </head> <body> <h1>Headline</h1> <p>Information of interest.</p> </body> </html>
Beschreiben Sie, wie Adressen in
sed
verwendet werden könnten, um nur das Elementbody
und seinen Inhalt anzuzeigen. -
Welcher
sed
-Ausdruck entfernt alle Tags aus einem HTML-Dokument, wobei nur der gerenderte Text erhalten bleibt? -
Dateien mit der Erweiterung
.ovpn
sind sehr beliebt, um VPN-Clients zu konfigurieren, da sie nicht nur die Einstellungen, sondern auch den Inhalt von Schlüsseln und Zertifikaten für den Client enthalten. Diese Schlüssel und Zertifikate befinden sich ursprünglich in separaten Dateien, so dass sie in die Datei.ovpn
kopiert werden müssen. Es folgt ein Auszug aus einer.ovpn
-Vorlage:client dev tun remote 192.168.1.155 1194 <ca> ca.crt </ca> <cert> client.crt </cert> <key> client.key </key> <tls-auth> ta.key </tls-auth>
Angenommen, die Dateien
ca.crt
,client.crt
,client.key
undta.key
befinden sich im aktuellen Verzeichnis, wie würde die Template-Konfiguration durchsed
modifiziert werden, um jeden Dateinamen durch seinen Inhalt zu ersetzen?
Zusammenfassung
Diese Lektion behandelt die beiden wichtigsten Linuxbefehle im Zusammenhang mit regulären Ausdrücken: grep
und sed
. Skripte und zusammengesetzte Befehle stützen sich auf grep
und sed
, um eine breite Palette von Textfilter- und Parsingaufgaben auszuführen. Die Lektion behandelt die folgenden Schritte:
-
Wie man
grep
und seine Variationen wieegrep
undfgrep
verwendet. -
Wie man
sed
und seine internen Anweisungen zur Textmanipulation verwendet. -
Beispiele für Anwendungen regulärer Ausdrücke mit
grep
undsed
.
Lösungen zu den geführten Übungen
-
Der Befehl
last
zeigt eine Liste der zuletzt eingeloggten Benutzer, einschließlich ihrer Herkunfts-IPs. Wie würde der Befehlegrep
verwendet werden, um die Ausgabe vonlast
so zu filtern, das nur die genannte IPv4-Adresse anzeigt wird und alle zusätzlichen Informationen in der entsprechenden Zeile verwirft?last -i | egrep -o '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}'
-
Welche Option sollte an
grep
übergeben werden, um die Ausgabe, die durch den mit der Option-print0
ausgeführten Befehlfind
erzeugt wird, korrekt zu filtern?Die Option
-z
oder--null-data
, wie infind . -print0 | grep -z expression
. -
Der Befehl
uptime -s
zeigt das letzte Datum an, an dem das System eingeschaltet wurde, wie in 2019-08-05 20:13:22. Was wird das Ergebnis des Befehlsuptime -s | sed -e 's/(.*) (.*)/\1/'
sein?Es wird ein Fehler auftreten. Standardmäßig sollten Klammern escaped werden, um Rückverweise in
sed
zu verwenden. -
Welche Option sollte man
grep
geben, damit es übereinstimmende Zeilen zählt, anstatt diese anzuzeigen?Option
-c
.
Lösungen zu den offenen Übungen
-
Die Grundstruktur einer HTML-Datei beginnt mit den Elementen
html
,head
undbody
, zum Beispiel:<html> <head> <title>News Site</title> </head> <body> <h1>Headline</h1> <p>Information of interest.</p> </body> </html>
Beschreiben Sie, wie Adressen in
sed
verwendet werden könnten, um nur das Elementbody
und seinen Inhalt anzuzeigen.Um nur
body
zu zeigen, sollten die Adressen/<body>/,/<\/body>/
lauten, wie insed -n -e '/<body>/,/<\/body>/p'
. Die Option-n
wirdsed
anweisen, dass standardmäßig keine Zeilen ausgegeben werden, daher der Befehlp
am Ende des Ausdrucks vonsed
, um übereinstimmende Zeilen dennoch auszugeben. -
Welcher
sed
-Ausdruck entfernt alle Tags aus einem HTML-Dokument, wobei nur der gerenderte Text erhalten bleibt?Der
sed
-Ausdrucks/<[^>]*>//g
ersetzt jeden in<>
eingeschlossenen Inhalt durch eine leere Zeichenkette. -
Dateien mit der Erweiterung
.ovpn
sind sehr beliebt, um VPN-Clients zu konfigurieren, da sie nicht nur die Einstellungen, sondern auch den Inhalt von Schlüsseln und Zertifikaten für den Client enthalten. Diese Schlüssel und Zertifikate befinden sich ursprünglich in separaten Dateien, so dass sie in die Datei.ovpn
kopiert werden müssen. Es folgt ein Auszug aus einer.ovpn
-Vorlage:client dev tun remote 192.168.1.155 1194 <ca> ca.crt </ca> <cert> client.crt </cert> <key> client.key </key> <tls-auth> ta.key </tls-auth>
Angenommen, die Dateien
ca.crt
,client.crt
,client.key
undta.key
befinden sich im aktuellen Verzeichnis, wie würde die Template-Konfiguration durchsed
modifiziert werden, um jeden Dateinamen durch seinen Inhalt zu ersetzen?Der Befehl
sed -r -e 's/(^[^.]*)\.(crt|key)$/cat \1.\2/e' < client.template > client.ovpn
ersetzt jede Zeile, die mit
.crt
oder.key
endet, durch den Inhalt einer Datei, deren Name gleich der Zeile lautet. Die Option-r
weistsed
an, erweiterte reguläre Ausdrücke zu verwenden, währende
am Ende des Ausdruckssed
anweist, Übereinstimmungen durch die Ausgabe des Befehlscat \1.\2
zu ersetzen. Die Rückverweise\1
und\2
entsprechen dem Dateinamen und der Dateiendung, die in der Übereinstimmung gefunden wurden.