Wie funktioniert dieser 'sed'-Substitutionsbefehl mit vielen @ -Zeichen?

8

Kann jemand erklären, wie dieser sedBefehl funktioniert?

sed 's@+@ @g;s@%@\\x@g' | xargs -0 printf "%b"
Raj
quelle
3
Der normale Weg, dies zu tun, ist die Verwendung von Schrägstrichen, aber das kann umständlich werden, wenn Sie etwas suchen und durch Schrägstriche ersetzen. Dies ist hier nicht der Fall, und obwohl es vollkommen in Ordnung ist, verwirrt es zukünftige Betreuer wie Sie.
Thorbjørn Ravn Andersen
2
… Und führt sie dazu, auf seddiese Weise etwas Neues zu lernen ! :)
Nachtisch

Antworten:

15

In sed werden Ersatzbefehle normalerweise als geschrieben s/pattern/replacement/options. Es ist jedoch nicht erforderlich, es zu verwenden /- Sie können andere Zeichen verwenden, wenn es zweckmäßig ist, also könnte es s@pattern@replacement@optionsoder sein s:foo:bar:g. s@+@ @gist wie s/+/ /g- alle +durch Leerzeichen ersetzen . Ersetzt in ähnlicher Weise s@%@\\x@galle %durch \x(ein einzelner Backslash ist ein Escape-Zeichen in sed, Sie benötigen also zwei, um einen tatsächlichen Backslash zu erhalten).

Eine Zeichenfolge wie foo+%2Fbarwird dann foo \x2Fbar. printf "%b"erweitert die Backslash-Escape-Sequenzen wie \x2F(das ASCII-Zeichen, dessen hexadezimaler Wert 2F ist /), um Ihnen schließlich zu geben foo /bar.

muru
quelle
2
Kurz gesagt, ein URL-> Dateinamen-Decoder.
Thorbjørn Ravn Andersen
10

Der Befehl, nach dem Sie zum Dekodieren von +es und %Sequenzen aus URLs fragen, ist nicht nur ein sedBefehl, sondern eine Pipeline , die Eingaben verarbeitet sedund xargszur weiteren Verarbeitung an diese weiterleitet. Schauen wir uns zuerst den sedBefehl an:

sed 's@+@ @g;s@%@\\x@g'

Sie können mehr gewöhnt werden sie mit zu sehen , /anstatt @als Separator, die leicht hier da getan haben , ohne Komplikation könnte , /erscheint in keiner der Suchmuster noch eine der Ersetzungstexte. Dieser Befehl ist äquivalent:

sed 's/+/ /g;s/%/\\x/g'

Wie /, @ist eine ganz gute Interpunktionszeichen für sed.

In jeder Eingabezeile:

  1. s@+@ @g( s/+/ /g) ersetzt ( s) Vorkommen von +durch ein Leerzeichen. Dies betrifft alle +es in einer Zeile ( g), nicht nur die erste.

  2. ; beendet die Aktion ("Befehl") und ermöglicht es Ihnen, eine andere im selben "Skript" anzugeben.

  3. s@%@\\x@g( s/%/\\x/g) ersetzt ( s) Vorkommen von %mit \x. Nach wie vor wirkt es auf alle und nicht nur auf die erste jeder Zeile ( g).

    In \\xder \\stellt nur eine dar, \weil \sie eine besondere Bedeutung hat sed. Seine besondere Bedeutung ist eigentlich das Zeichen, mit dem Sie die besondere Bedeutung eines anderen Zeichens entfernen, das danach kommt und das sonst eine besondere Bedeutung hätte. Also muss es als entkommen \\.


Schauen wir uns nun den xargsBefehl an, dessen Zweck die Ausführung ist printf.

xargserstellt Befehlszeilen. Wenn Sie laufen , wo ein oder mehr Wort, läuft mit zusätzlichen Befehlszeilenargumente von seinem Eingang zu lesen. In diesem Fall ist die Eingabe in die Ausgabe von aufgrund der Pipe ( ). Normalerweise interpretiert jedes Leerzeichen in seiner Eingabe so, dass der Text vor und nach dem Schreiben separate Argumente darstellt. Mit dieser Option werden jedoch Argumente beim Auftreten des Nullzeichens aufgeteilt .xargs command...command...xargscommand...xargssed|xargs-0

Bei der beabsichtigten Verwendung Ihres Befehls wird kein Nullzeichen angezeigt und xargsnur printf %bmit einem zusätzlichen Befehlszeilenargument ausgeführt, der Ausgabe des sedBefehls. Während also nicht gleichwertig in der Regel in diesem Fall die gesamte Pipeline könnte statt wie diese verwenden geschrieben wurde Befehl Substitution statt xargs:

printf '%b\n' "$(sed 's/+/ /g;s/%/\\x/g')"

Was printfhier zu tun ist, wie Muru sagt,%b verbraucht und druckt der Formatbezeichner ein Argument (wie %s), bewirkt jedoch, dass Backslash-Escapezeichen - wie sie vom sedBefehl auf der linken Seite der Pipe generiert wurden - übersetzt werden in die Zeichen, die sie darstellen .

Angenommen, ich führe diesen Befehl aus und übergebe ihn http://foldoc.org/debugging%20by%20printfals Eingabe. Ich bekomme http://foldoc.org/debugging by printfals Ausgabe, weil die %20Sequenzen in Leerzeichen übersetzt werden.

Eliah Kagan
quelle
3

Das ist das Schöne daran sed, es wendet seine Paradigmen auf sich selbst an ... Nach dem Befehl (wie soder troder nichts) wird das nächste Zeichen als Trennzeichen betrachtet.

Sie sollten mit Bedacht wählen, um Interferenzen mit der Shell und dem Befehl selbst zu vermeiden und die Sache lesbar zu halten, aber es ist absolut gültig, etwas so Schreckliches zu schreiben wie:

echo 'arrival' | sed srarbrg

... und brrivblals Ergebnis erhalten, was Sie erwarten. Sie können Spaß daran haben, es wirklich kryptisch zu machen, wie in:

echo 'arrival' | sed s\fa\fb\fg   # \f is form feed, chr(12)

Die übliche Verwendung besteht darin, den Schrägstrich als Trennzeichen zu verwenden. Wenn Ihr Ausdruck jedoch das Trennzeichen enthält, ist es einfacher, die Absicht zu erfassen. Ihr Trennzeichen kann alles im ASCII8-Bereich sein (Multibyte-Trennzeichen, die beispielsweise £einen Fehler hervorrufen).

Denken Sie daran, das Ziel ist es, die Dinge einfacher und nicht kryptischer zu machen.

Marabiloso
quelle
Mit der kryptischen Idee ausgeführt, ist dies ein gültiger sed-Befehl, obwohl er nichts Nützliches sed "snack is an apple or something" <<< "I sed your snack is an apple or something"
bewirkt
Nett! Ja, Sie können sedBefehle auch als Denksportaufgaben verwenden. Wie geekig ist das?
Marabiloso