Streameditor sed
sed ist ein Stromeditor (stream editor).Ein Streameditor wird für grundlegende Texttransformationen auf einen Eingabestrom (einer Datei oder aus einer Verarbeitungskette) verwandt.
Obwohl in einigen Aspekten ähnlich zu einem Editor, der Bearbeitungen nach Skript erlaubt (wie Ed), führt Sed nur einen Durchlauf über die Eingabe(n) durch und ist somit effizienter. Allerdings ist es die Fähigkeit von Sed, Text in einer Verarbeitungskette zu filtern, die ihn besonders gegenüber anderen Arten von Editoren auszeichnet.
sed [-V] [--version] [--help] [-n] [--quiet] [--silent]
[-l N] [--line-length=N] [-u] [--unbuffered]
[-E] [-r] [--regexp-extended]
[-e Skript] [--expression=script]
[-f Skriptdatei] [--file=Skriptdatei]
[script-if-no-other-script]
[Datei …]
Eine komplete Übersicht des Kommandos finden Sie in den MAN-Pages man sed
Sie haben sich dem Sourcecode eine Programmauschnits anzeigen lassen und wollen den ine einem eigenen Programm weiter verarbeiten.
Leider wird der Soucecode als eine laaaaange Zeile angezeigt.
Mittels des sed können Sie die Datei jedoch an gewünschten Stellen umbrechen
Hier soll das nach </div> und nach </span> erfolgen.
sed -i 's/<\/div>/<\/div>\n/g' datei.text
sed -i 's/<\/span>/<\/span>\n/g' datei.text
sed: Der Text-Editor für das Terminal.
-i: Ändert die Datei direkt (in-place).
's/ALT/NEU/g': Ersetzt jedes Vorkommen
ALT durch NEU
\n: Steht für den Zeilenumbruch der an NEU angehängt wird.
(global, g) wendet auf jedes Vorkommen an.
Als Trennzeichen wird häufig der / verwendet.
Das macht das etwas unleserlich wenn ein / auch
Teil des Ausdrucks ist.
In diesem Fall muss er im Ausduck mit \/ maskiert werden.
Als Trennzeiche kann aber auch ein anders Zeichen
verwendet werden.
Z.B. # oder | es sollte nur nicht im Ausdruck vorkommen.
Weiter unten sehen Sie dazu ein Beispel,
Tipp für macOS:Nutzen Sie auf dem Mac einen leeren String nach -i,
da das dortige sed diesen zwingend benötigt:
sed -i '' 's/<\/div>/<\/div>\n/g' datei.text
Wenn man das häufiger benötigt kann man sehr gut in einem Bashscript ablegen.
Natürlich ist es immer probematisch, wenn eine Datei direkt geändert wird. Falls dabei etwas schiefgeht, steht man plötzlich ohne seine Daten da
sed hat dafür eine elegante Lösung: Die Erzeugung einer Backupdatei.
sed -ibak '' 's/<\/div>/<\/div>\n/g' datei.text
erzeugt eine datei.txtbak als Backupr
Achtung: wenn den Befehl mehrfach eingeben, um etwas auszuprobieren, wird die Datei immer wieder überschrieben und Sie stehen am Ende wieder ohne Daten da.
Es empfiehlt sich zunächst ohne den Parameter -i zu arbeiten.
Das Ergebnis wird dann auf dem Terminal ausgegeben oder si leiten die Ausgabe per Pipe in eine Datel um
sed 's/<\/div>/<\/div>\n/g' datei.text
Wenn Sie nun wie oben vorgeschlagen nach 2 Kriterien suchen und diese ändern wollen, dann sollten wir unseren Aufruf ändern.
sed erlaubt uns mehrere scripte per -e an das Command zu übergeben.
sed -e 's/<\/div>/<\/div>\n/g' -e 's/<\/span>/<\/span>\n/g' datei.text
-e Skript, --expression=Skript
Jeder expression beinhaltet ein script, das von sed abgearbeitet wird.
In unserem Fall ein substitute
s/RegAusdr/Ersatz/
Sucht die Entsprechung von RegAusdr im Musterbereich und
falls erfolgreich, ersetzt den passenden Teil mit Ersatz.
Das liefert schon mal ein Ergebnis, aber es lässt sich noch optimieren : Alternative (bessere Lesbarkeit)
Wenn Sie statt des Schrägstrichs / ein anderes Trennzeichen wie das Pipe-Zeichen | (oder ein Rautezeichen #) für den s-Befehl nutzen, müssen Sie die HTML-Slashes nicht mehr mit Backslashes maskieren:
sed -E 's#(</div>|</span>)#\1\n#g' datei.text
-E: Aktiviert die erweiterten regulären Ausdrücke (ERE),
wodurch wir die runden Klammern und den Oder-Strich ohne Backslashes nutzen können.
s#(</div>|</span>)#
Sucht entweder nach </div> ODER nach </span>
und speichert den Treffer in einer nummerierten Gruppe.
Auf die Gruppe kann bei der Änderung wieder
zugegriffen werden.
Der Ersatz kann das besondere Zeichen & enthalten, um
auf den Teil des Musterbereichs zu verweisen, der
passte, und die besonderen Maskiersequenzen
\1 bis \9, die auf die entsprechenden passenden
Teilausdrücke in RegAusdr verweisen
\1\n# Fügt den gefundenen Text (Gruppe 1) wieder ein und setzt
den Zeilenumbruch (\n) direkt dahinter.
g global d.h. jeder gefundene Ausdruck wird ersetzt.
Ohne -i: Das Ergebnis wird direkt im Terminal ausgegeben,
ohne die Originaldatei zu verändern.
Damit können wird erst einel unbesorgt testen und verschiedene
Möglichkeiten ausprobieren, bevor wir das Ergebnis per
sed -E 's#(<>/div>|</span>)#\1\n#g' datei.text > ergebnis.txt
in eine andere Datei scheiben oder wir verwenden -i für "inPlace"
Weiteres Beispiel
sed -i '/Herkunft: startup_1_0\.inc/!s/startup_1_0/startup/g' startup.incErsetzt alle Vorkommen die startup_1_0 enthalten aber nicht Teil von Herkunft: startup_1_0 sind durch startup
# SED
Diese Datei wurde von einem Programm erzeugt. Sie soll so umgewandelt werden, dass sie als JSON Tabelle verwendet werden kann.
```
2019.01.01|1||8:17.37|16:27.33| 8:09.55|12:29.27| 17.00°| -3.1
2019.01.02|2||8:17.07|16:28.08| 8:11.01|12:29.56| 17.09°| -3.5
2019.01.03|3||8:16.35|16:28.48| 8:12.12|12:30.25| 17.18°| -4.0
2019.01.04|4||8:16.01|16:29.30| 8:13.29|12:30.53| 17.28°| -4.5
2019.01.05|5||8:15.24|16:30.16| 8:14.51|12:31.21| 17.38°| -5.0
:
2019.12.27|27||8:24.12|16:30.09| 8:05.57|12:26.59| 16.69°| -0.6
2019.12.28|28||8:24.24|16:30.57| 8:06.32|12:27.29| 16.74°| -1.1
2019.12.29|29||8:24.34|16:31.47| 8:07.13|12:27.59| 16.79°| -1.6
2019.12.30|30||8:24.40|16:32.41| 8:08.01|12:28.29| 16.85°| -2.1
2019.12.31|31||8:24.43|16:33.37| 8:08.54|12:28.58| 16.92°| -2.6
(END)
```
```
cat 2019_49.98081241_8.39973450.dat | sed -e 's/^\(.*\)$/"\1",/g'
```
Das Ergebnis hat auch in der letzten Zeile noch ein ,
```
"2019.12.28|28||8:24.24|16:30.57| 8:06.32|12:27.29| 16.74°| -1.1",
"2019.12.29|29||8:24.34|16:31.47| 8:07.13|12:27.59| 16.79°| -1.6",
"2019.12.30|30||8:24.40|16:32.41| 8:08.01|12:28.29| 16.85°| -2.1",
"2019.12.31|31||8:24.43|16:33.37| 8:08.54|12:28.58| 16.92°| -2.6",
```
Um alles auf einmal zu erzeugen, wird mittele Pipe ein weiterer SED gestartet. Der zweite SED fügt vor der ersten Zeile [ ein und ersetzt das letzte , durch einen Linefeed und ] und schreibt das Ergebnis in eine Datei
```
cat 2019_49.98081241_8.39973450.dat | sed -e 's/^\(.*\)$/"\1",/g' |
sed -e '1 i\[' -e '$ s/\([0-9]"\),$/\1\n]/' > 2019_coords.json
```
Die Pipe kann aber auch noch weggelessen werden, wenn alle e-Scripts in einem Kommando angegeben werden.
```
cat 2019_49.98081241_8.39973450.dat |
sed -e 's/^\(.*\)$/"\1",/g' -e '1 i\[' -e '$ s/\([0-9]"\),$/\1\n]/' >
2019_coords_1.json
detlef@i7-dh:/data/../data$ head -3 2019_coords_1.json
[
"2019.01.01|1||8:17.37|16:27.33| 8:09.55|12:29.27| 17.00°| -3.1",
"2019.01.02|2||8:17.07|16:28.08| 8:11.01|12:29.56| 17.09°| -3.5",
detlef@i7-dh:/data/../data$ tail -3 2019_coords_1.json
"2019.12.30|30||8:24.40|16:32.41| 8:08.01|12:28.29| 16.85°| -2.1",
"2019.12.31|31||8:24.43|16:33.37| 8:08.54|12:28.58| 16.92°| -2.6"
]
detlef@i7-dh:/data/../data$
```
Diese Form setzt auch noch hinter ] ein ",
der regular Expression verwendet einen per \ maskierten Substring \ ( \\) der mittels .* alle Zeichen der Zeile erfasst.
```
cat 2019_coords_rheim.dat | sed -e 's/^\(.*\)$/\1",/g'
```
Das geht jedoch einfacher mit :
```
cat 2019_coords_rheim.dat | sed -e 's/$/",/g
```
Hier wird davon ausgegangen, dass das letzte Zeichen jeweils eine Ziffer ist.
Damit wird nur beim letzten Eintrag noch ein überflüssigen , gesetzt.
```
cat 2019_coords_rheim.dat | sed -e 's/\([0-9]\)$/\1",/g
"2019.12.31|31||8:24.43|16:33.37| 8:08.54|12:28.58| 16.92°| -2.6",
]
```
------
In eienrm Webauftritt soll ermittelt werden, wo eine Zentrale Datei Termin und un Welcher Version verwendet wird. Die Ausgabe soll nach der Version aufsteigen in eine Datei zur weiteren Verarbeitung geschieben werden.
#/bin/bash
OUTFILE=/tmp/menu.txt
cd /data/htdocs
find -P . -name "*.php" -exec grep -H -n "new Menu_" {} \; |
sed -e 's/^.*\(Menu.*[0-5]\).*$/\1:&/g' | sort > $OUTFILE
cat $OUTFILE | wc -l