Wie speichert man einen komplexen regulären Ausdruck für die mehrfache Wiederverwendung in sed?

12

Bei der Verwendung sederstelle ich oft ziemlich komplizierte und komplizierte reguläre Ausdrücke, die ich zweimal in einer Datei abgleichen muss. Gibt es eine Möglichkeit für mich, diesen regulären Ausdruck zu speichern und ihn nur zweimal zu referenzieren?

Vielleicht etwas, das so aussieht?

sed ' complicated_regex=/^(([a-f0-9]{32})+([a-zA-Z0-9=]{{$i}})?)+$/
s/complicated_regex:complicated_regex/simple-output/
' my_file

Update: Eine Antwort hat die Lösung der Verwendung einer Bash-Variablen vorgestellt. Das funktioniert nicht. Gegeben a test.txt.

#test.txt
foo bar
bar foo

Und das Drehbuch

#!/bin/bash

VALUE='foo \([a-z]\+\)'

sed 's/"${VALUE}"/foo happy \1/' test.txt

Dies sollte die Ausgabe erzeugen

foo happy bar
bar foo

Aber stattdessen bekomme ich den Fehler

sed: -e expression #1, char 24: invalid reference \1 on `s' command's RHS
Cory Klein
quelle
Wenn Sie Perl verwenden, können Sie frühere Teile des Ausdrucks innerhalb des Ausdrucks perl -pe 's/^(([a-f0-9]{32})+([a-zA-Z0-9=]{{$i}})?)+:\1$/simple_output/' my_file
referenzieren
1
Wenn Sie etwas zu kompliziert für sed finden, zögern Sie nicht, awk oder perl zu nehmen.
Gilles 'SO - hör auf böse zu sein'
2
@Cory: Ihr Beispiel funktioniert gut, wenn Sie die richtige Syntax haben. Sie haben die "$ Variable" immer noch in 'einfache Anführungszeichen' eingeschlossen, die sie vor der erwarteten Shell-Erweiterung verbirgt ... es sollte seinsed 's/'"${VALUE}"'/foo happy \1/' test.txt
Peter.O

Antworten:

7

Sie können Shell-Variablen verwenden:

complicated_regex='(([a-f0-9]{32})+([a-zA-Z0-9=]{{$i}})?)+'
sed s/^"$complicated_regex":"$complicated_regex"\$/'simple-output'/ my_file

Ich bin mir nicht sicher, was Sie damit gemeint haben $i, aber Sie müssen es möglicherweise außerhalb von einfachen Anführungszeichen setzen:

complicated_regex='(([a-f0-9]{32})+([a-zA-Z0-9=]{{'"$i"'}})?)+'
Stéphane Gimenez
quelle
Dies funktioniert natürlich nur, wenn der sedBefehl von der Shell aus aufgerufen wird, aber es gibt eine ähnliche Lösung für fast alle Programmiersprachen. (Und ich denke nicht, dass es möglich ist, Variablen innerhalb zu verwenden sed.)
Stéphane Gimenez
Hrm. Wenn Sie dies versuchen, scheinen die Rückreferenzen unterbrochen zu sein. s/$complicated_regex/\1/gibt einen Fehler aus, der besagt, dass dies eine ungültige Referenz ist.
Cory Klein
Ah, vielleicht meine Schuld, ich bin es gewohnt, Variablen zu ersetzen. Siehe aktualisierte Antwort.
Stéphane Gimenez
Sie müssen die Anker aus der Variablen entfernen und sie in das sed-Skript sed "s/^${complicated_regex}:${complicated_regex}\$/simple-output/" my_file
einfügen
Duh! Ja, ich habe vergessen zu überprüfen, ob mir eine gültige Regex-Verkettung zur Verfügung gestellt wurde :-)
Stéphane Gimenez
0

Der einfachste Weg, einen Shell-Variablenwert einzufügen sedund sich keine Gedanken darüber zu machen, wie sich Ihr Backslash-Escape für den Rest Ihres sedSkripts ändern muss , besteht darin, alles in einfache Anführungszeichen außer der Variablen zu setzen und dies in doppelte Anführungszeichen zu setzen.

Alle folgenden Codebeispiele setzen voraus: VALUE='foo \([a-z]\+\)'

Der folgende fehlerhafte Code schlägt fehl, weil die Variable VALUEnicht erweitert wird:

sed 's/"${VALUE}"/foo happy \1/' test.txt

Der folgende fehlerhafte Code schlägt fehl, weil der Backslash \1von der Shell gefressen wird (weil er in doppelten Anführungszeichen und nicht in einfachen Anführungszeichen steht), bevor er sedjemals angezeigt wird:

sed "s/${VALUE}/foo happy \1/" test.txt

Der folgende Code funktioniert wie erwartet:

sed 's/'"${VALUE}"'/foo happy \1/' test.txt

Der folgende Code funktioniert auch:

sed "s/${VALUE}/foo happy \\1/" test.txt

Folgendes auch:

sed s/"${VALUE}"/foo\ happy\ \\1/ test.txt

Aber warum kompliziert werden? Einfache Anführungszeichen um ein sedSkript machen alles viel klarer, insbesondere für die Nicht-Shell-Scripting-Gurus, die Ihren Code lesen. Mein bevorzugter Weg ist es wiederum, einfache Anführungszeichen nur für die Variablenerweiterung in doppelte Anführungszeichen zu setzen und direkt zu einfachen Anführungszeichen zurückzukehren:

sed 's/'"${VALUE}"'/foo happy \1/' test.txt
Platzhalter
quelle