GNU/Linux >> LINUX-Kenntnisse >  >> Linux

Wie kann sichergestellt werden, dass die in die `sed`-Ersetzung interpolierte Zeichenfolge allen Metazeichen entgeht?

Ich habe ein Skript, das einen Textstrom liest und eine Datei mit sed-Befehlen generiert, die später mit sed -f ausgeführt wird . Die generierten sed-Befehle sind wie folgt:

s/cid:[email protected]/https://mysite.com/files/1922/g
s/cid:[email protected]/https://mysite.com/files/1923/g
s/cid:[email protected]/https://mysite.com/files/1924/g

Nehmen Sie das Skript an, das den sed generiert Befehle ist etwas wie:

while read cid fileid
do
    cidpat="$(echo $cid | sed -e s/\./\\./g)"
    echo 's/'"$cidpat"'/https://mysite.com/files/'"$fileid"'/g' >> sedscr
done

Wie kann ich das Skript verbessern, um alle Regex-Metazeichen in der cid sicherzustellen string werden korrekt maskiert und interpoliert?

Akzeptierte Antwort:

Escape-Variablen, die auf der linken und rechten Seite eines s verwendet werden Befehl in sed (hier $lhs und $rhs bzw.), würden Sie Folgendes tun:

escaped_lhs=$(printf '%sn' "$lhs" | sed 's:[][\/.^$*]:\&:g')
escaped_rhs=$(printf '%sn' "$rhs" | sed 's:[\/&]:\&:g;$!s/$/\/')

sed "s/$escaped_lhs/$escaped_rhs/"

Beachten Sie, dass $lhs darf kein Zeilenumbruchzeichen enthalten.

Das heißt, auf der LHS alle Regexp-Operatoren maskieren (][.^$* ), das Escapezeichen selbst ( ) und das Trennzeichen (/ ).

Auf der rechten Seite müssen Sie nur & maskieren , das Trennzeichen, den umgekehrten Schrägstrich und das Zeilenumbruchzeichen (was Sie tun, indem Sie am Ende jeder Zeile außer der letzten einen umgekehrten Schrägstrich einfügen ($!s/$/\/ )).

Das setzt voraus, dass Sie / verwenden als Trennzeichen in Ihrem sed s Befehle und dass Sie Erweiterte REs nicht aktivieren mit -r (GNU sed /ssed /ast /busybox sed ) oder -E (BSDs, ast , aktuelles GNU, aktuelles busybox) oder PCREs mit -R (ssed ) oder Erweiterte REs mit -A /-X (ast ), die alle über zusätzliche RE-Operatoren verfügen.

Ein paar Grundregeln für den Umgang mit beliebigen Daten:

  • Verwende echo nicht
  • zitieren Sie Ihre Variablen
  • Berücksichtigen Sie die Auswirkungen des Gebietsschemas (insbesondere seines Zeichensatzes:Es ist wichtig, dass die Escapezeichen sed Befehle werden im gleichen Gebietsschema wie sed ausgeführt Befehl mit dem escaped Strings (und mit demselben sed Befehl) zum Beispiel)
  • Vergessen Sie nicht das Zeilenumbruchzeichen (hier sollten Sie prüfen, ob $lhs enthält und Maßnahmen ergreifen).

Eine andere Möglichkeit ist die Verwendung von perl statt sed und übergeben Sie die Zeichenfolgen in der Umgebung und verwenden Sie das Q /E perl Regexp-Operatoren, um Strings wörtlich zu nehmen:

A="$lhs" B="$rhs" perl -pe 's/Q$ENV{A}E/$ENV{B}/g'

perl (standardmäßig) wird nicht vom Zeichensatz des Gebietsschemas beeinflusst, da es oben die Zeichenfolgen nur als Arrays von Bytes betrachtet, ohne sich darum zu kümmern, welche Zeichen (falls vorhanden) sie für den Benutzer darstellen. Mit sed , könnten Sie dasselbe erreichen, indem Sie das Gebietsschema auf C festlegen mit LC_ALL=C für alle sed Befehle (obwohl dies auch die Sprache von Fehlermeldungen beeinflusst, falls vorhanden).

Verwandte:Verwendung von sed mit Sonderzeichen?
Linux
  1. Wie kombinieren Sie alle Zeilen, die mit einem Backslash-Zeichen enden?

  2. Wie ersetze ich eine Zeichenfolge durch eine Zeichenfolge, die Slash mit Sed enthält?

  3. Sed:Alle Vorkommen einer Zeichenfolge außer der ersten löschen?

  4. Wie finde ich alle Dateien, die keine Textzeichenfolge enthalten?

  5. Wie grep ich eine Zeichenfolge in einem Verzeichnis und allen seinen Unterverzeichnissen?

So verwenden Sie sed zum Suchen und Ersetzen von Zeichenfolgen in Dateien

So verwenden Sie Sed zum Suchen und Ersetzen einer Zeichenfolge in einer Datei

Wie baut man ein Linux-Kernel-Modul so, dass es mit allen Kernel-Releases kompatibel ist?

So entfernen Sie alle Dateien, die mit einer bestimmten Zeichenfolge in Linux beginnen

So finden Sie Dateien, die eine bestimmte Suchzeichenfolge nicht enthalten

So erfassen Sie alle Festplatten, die kein Dateisystem haben