CLI: Platzhalter innerhalb von Ordnern durch Variablen ersetzen

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:

  • Das grep Zeilen liest.
  • xargs kann Input an was anderes weiterreichen.
  • sed kann Dinge ersetzen.

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
Dankend zusammengeführt aus der ASCII-Tabelle gelistet auf torsten-horn.de.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert