Nehmen wir an wir hätten einen Ordner mit einigen Dateien. Und zwei Textbausteine.
Ein Textbaustein soll den anderen ersetzen.
Der zu ersetzende steht innerhalb von Dateien, der andere innerhalb einer Variable.
Wie machen wir das mit Linux Bordmitteln?
Hier ein grep-xargs-sed
Ansatz.
TL;DR
- Liste von
sed
-Trennzeichen. - Snippet um innerhalb eines Ordners Texte mit dem Begriff
suche_nach
mit dem Wert einer Variablen zu ersetzen.
$ersetze_mit="baum"
grep -rl "suche_nach" ./ordner | xargs --no-run-if-empty sed -i "s/suche_nach/$ersetze_mit/g";
Use-Cases
- Docker Konfigurations-Dateien vorbereiten.
- Konfigurations-Dateien Dateien auf erweiterten Ordner-Strukturen automatisiert bearbeiten.
- Massenhafte CSV/JSON/{choose-your-poison} Dateien verarbeiten.
- Not recommended but possible: Datenbank-Dumps bearbeiten.
Annahmen
Nehmen wir an und hätten folgende Ordnerstruktur.
├── durchsuche-mich
│ ├── eine-datei
│ ├── eine-url
│ ├── ein-windows-pfad
│ └── mail
└── sed-mask.sh
Dazu einen ein Text der in manchen Dateien existiert (suche_nach
).
Und der mit einer Umgebungsvariable ($ersetze_mit
) ersetzt werden soll.
Ein grep-xargs-sed
Ansatz
Wir wissen:
Angenommen eine Umgebungsvariable ersetze_mit
wäre Verfügbar, dann könnte so etwas in sed-mask.sh
stehen und funktionieren.
grep -rl "suche_nach" ./durchsuche-mich | xargs --no-run-if-empty sed -i "s/suche_nach/$ersetze_mit/g";
Wie können wir Pfade mit sed
ersetzen?
Nehmen wir mal weiter an…
Was passiert wenn ersetze_mit
ein Pfad wäre. Ein Pfad der per Slash (/
) getrennt wird?
Genau es knallt.
sed: -e expression #1, char 20: unknown option to `s'
Und zwar ganz gemütlich, aber richtig.
sed
sei Dank können wir hier entgegensteuern.
grep -rl "suche_nach" ./durchsuche-mich | xargs --no-run-if-empty sed -i "s|suche_nach|$ersetze_mit|g";
Dieser Befehl nimmt einfach mal ein Pipe anstelle von Slashs als Trennzeichen.
Voll cool, oder?
Etwas mehr Kontext dazu, liefern die Docs:
Substitute the replacement string for instances of the BRE in the pattern space.
Any character other than backslash or newline can be used instead of a slash to delimit the BRE and the replacement.
Within the BRE and the replacement, the BRE delimiter itself can be used as a literal character if it is preceded by a backslash.
source: [2addr] s/BRE/replacement/flags
Nach dem ersten lesen, wusste ich immer noch nicht was möglich ist.
Irgendwie fehlte eine Liste von möglichen Trennern.
Liste von möglichen sed
-Trennzeichen
Also wir wissen, das andere Trennzeichen möglich sind.
Nicht alle Zeichen.. aber genug.
Die Auswahl beschränkt sich auf Ein-Byte große Zeichen.
Zumindest der Fehlermeldung nach wenn ich Umlaute als Trennzeichen einsetze.
sed: -e expression #1, char 2: delimiter character is not a single-byte character
Das grenzt die Auswahl noch stärker ein.
Backslash und new lines sind auch nicht erlaubt.
Streichen wir noch das Alphabet und Zahlen erhalten wir folgende mögliche Trennzeichen.
NUL (^@) | SOH (^A) | STX (^B) |
ETX (^C) | EOT (^D) | ENQ (^E) |
ACK (^F) | BEL (^G) | BS ( ^H) |
TAB (^I) | VT ( ^K) | FF ( ^L) |
SO ( ^N) | SI ( ^O) | DLE (^P) |
DC1 (^Q) | DC2 (^R) | DC3 (^S) |
DC4 (^T) | NAK (^U) | SYN (^V) |
ETB (^W) | CAN (^X) | EM ( ^Y) |
SUB (^Z) | Esc (^[) | FS ( ^) |
GS ( ^]) | RS ( ^^) | US ( ^_) |
SP ( `) | ! | „ |
# | $ | % |
& | ‚ | („ |
) | * | + |
, | – | . |
/ | : | < |
= | > | ? |
@ | [„ | ] |
^ | _ | ` |
{ | | | } |
~ | DEL |
Schreibe einen Kommentar