Wenn Sie ein Schlüsselwort mit sed durch eine Zeichenfolge ersetzen möchten, versucht sed, Ihre Ersatzzeichenfolge zu interpretieren. Wenn die Ersatzzeichenfolge Zeichen enthält, die sed als besonders erachtet, z. B. ein '/' - Zeichen, schlägt dies fehl, es sei denn, Sie haben natürlich gemeint, dass Ihre Ersatzzeichenfolge Zeichen enthält, die sed angeben, wie sie sich verhalten sollen.
Ex:
VAR="hi/"
sed "s/KEYWORD/$VAR/g" somefile
Gibt es eine Möglichkeit, sed anzuweisen, nicht zu versuchen, die Ersatzzeichenfolge für Sonderzeichen zu interpretieren? Ich möchte nur in der Lage sein, ein Schlüsselwort in einer Datei durch den Inhalt einer Variablen zu ersetzen, unabhängig davon, um welchen Inhalt es sich handelt.
bash
shell-script
sed
Tal
quelle
quelle
sed
und diese nicht besonders sein sollen, entkommen Sie ihnen einfach mit einem Backslash.VAR='hi\/'
gibt kein solches Problem.sed(1)
interpretiert nur, was es bekommt. In Ihrem Fall wird dies über eine Shell-Interpolation erreicht. Ich glaube, Sie können nicht tun, was Sie wollen, aber lesen Sie das Handbuch. Ich weiß, dass Sie in Perl (das einen passablensed
Ersatz mit viel umfangreicheren regulären Ausdrücken darstellt) angeben können, dass eine Zeichenfolge wörtlich genommen werden soll. Überprüfen Sie erneut das Handbuch.Antworten:
Es gibt nur 4 Sonderzeichen im Ersatzteil: \, &, Newline und das Trennzeichen ( ref )
quelle
s///
ist kein regulärer Ausdruck, sondern nur eine Zeichenfolge (mit Ausnahme von Backslash-Escapezeichen und&
). Wenn die Ersatzschnur so lang ist, ist ein Shell-Einzeiler nicht Ihre Lösung.Sie können Perl anstelle von sed mit
-p
(Schleife über Eingabe annehmen) und-e
(Programm in der Befehlszeile angeben) verwenden. Mit Perl können Sie auf Umgebungsvariablen zugreifen, ohne diese in der Shell zu interpolieren. Beachten Sie, dass die Variable exportiert werden muss :Wenn Sie die Variable nicht überall exportieren möchten, geben Sie sie nur für diesen Prozess an:
Beachten Sie, dass sich die Syntax für reguläre Ausdrücke von Perl standardmäßig geringfügig von der von sed unterscheidet.
quelle
PATTERN
Umgebungsvariable gehen , nicht in Argumente. In jedem Fall wäre dies ein FehlerE2BIG
, den Sie ebenfalls erhalten würden, wenn Sie ihn verwenden würdensed
.Die einfachste Lösung, mit der die überwiegende Mehrheit der Variablenwerte immer noch korrekt behandelt wird, besteht darin, ein nicht druckbares Zeichen als Trennzeichen für
sed
den Ersatzbefehl zu verwenden.In können
vi
Sie jedem Steuerzeichen entkommen, indem Sie Strg-V eingeben (häufiger geschrieben als^V
). Wenn Sie also ein Steuerzeichen verwenden (^A
in diesen Fällen häufig als Trennzeichen), wird Ihrsed
Befehl nur unterbrochen, wenn dieses nicht druckbare Zeichen in der Variablen vorhanden ist, in die Sie einfügen.Sie würden also tippen
"s^V^AKEYWORD^V^A$VAR^V^Ag"
und wie Sie (invi
) erhalten würden, würde aussehen:Dies funktioniert so lange, wie
$VAR
das nicht druckbare Zeichen nicht enthalten^A
ist - was äußerst unwahrscheinlich ist.Wenn Sie Benutzereingaben an den Wert von übergeben
$VAR
, sind natürlich alle Wetten deaktiviert, und Sie sollten Ihre Eingabe gründlich bereinigen, anstatt sich darauf zu verlassen, dass Steuerzeichen für den durchschnittlichen Benutzer schwer zu tippen sind.Es gibt jedoch tatsächlich mehr zu beachten als die Trennzeichenfolge. Wenn es beispielsweise
&
in einer Ersatzzeichenfolge vorhanden ist, bedeutet dies "den gesamten übereinstimmenden Text". ZBs/stu../my&/
würde "stuff" durch "mystuff", "stung" durch "mystung" usw. ersetzen. Wenn Sie also ein Zeichen in der Variablen haben, das Sie als Ersatzzeichenfolge einfügen, aber das Literal verwenden möchten Nur der Wert der Variablen, dann müssen Sie einige Daten bereinigen, bevor Sie die Variable als Ersatzzeichenfolge in verwenden könnensed
. (Die Datenbereinigung kann jedochsed
auch durchgeführt werden.)quelle
sed
‚si
nsert Befehl. Essed
ist jedoch kein gutes Werkzeug, um große Textmengen auf komplexe Weise zu verarbeiten. Ich werde eine weitere Antwort veröffentlichen, die zeigt, wie das gehtawk
.Sie könnten stattdessen ein
,
oder ein|
verwenden, und es wird als Trennzeichen verwendet, und technisch können Sie alles verwendenvon der Manpage
Wie Sie sehen, sollten Sie am Anfang mit einem \ vor Ihrem Trennzeichen beginnen, dann können Sie es als Trennzeichen verwenden.
Aus der Dokumentation http://www.gnu.org/software/sed/manual/sed.html#The-_0022s_0022-Command :
Beispiel:
sed -e 'somevar|s|foo|bar|'
echo "Hello all" | sed "s_all_user_"
echo "Hello all" | sed "s,all,user,"
echo "Hello/ World" | sed "s,Hello/,Neo,"
quelle
/
und es wird das/
glücklich ignorieren, wie ich gerade betont habe . In der Tat können Sie sogar danach suchen und es in einer Zeichenfolge ersetzen >>> Ich habe mit einem Beispiel >>> diese bearbeitet Sachen sind nicht so sicher und Sie werden immer einensed
in erster Linie die Verwendung von , was ist Ihr Projekt?bash
ist NICHT für die Manipulation von Zeichenfolgen. Überhaupt, überhaupt, überhaupt. Es dient zur Dateimanipulation und Befehlskoordination . Es hat zufällig einige praktische Funktionen für Strings eingebaut, aber wirklich begrenzt und überhaupt nicht sehr schnell, wenn das die Hauptsache ist, die Sie tun. Siehe "Warum wird die Verwendung einer Shell-Schleife zum Verarbeiten von Text als schlechte Praxis angesehen?" Einige Werkzeuge , die sind für die Textverarbeitung ausgelegt sind, um von den meisten Grund zu leistungsfähigste:sed
,awk
und Perl.Wenn es zeilenbasiert ist und nur eine Zeile ersetzt werden muss, empfehle ich, der Datei selbst die Ersetzungszeile mit voranzustellen
printf
, die erste Zeile im Speicherbereich zu speichernsed
und sie nach Bedarf abzulegen . Auf diese Weise müssen Sie sich überhaupt nicht um Sonderzeichen kümmern. (Die einzige Annahme hier ist, dass$VAR
eine einzelne Textzeile ohne Zeilenumbrüche enthalten ist, wie Sie bereits in den Kommentaren gesagt haben.) Abgesehen von Zeilenumbrüchen könnte VAR alles enthalten , und dies würde unabhängig davon funktionieren.printf '%s\n'
druckt den Inhalt$VAR
unabhängig vom Inhalt als Literalzeichenfolge, gefolgt von einer neuen Zeile. (echo
In einigen Fällen werden andere Aufgaben ausgeführt, z. B. wenn der Inhalt von$VAR
mit einem Bindestrich beginnt. Er wird als Optionsflag interpretiert, an das übergeben wirdecho
.)Die geschweiften Klammern werden verwendet, um die Ausgabe
printf
dem Inhalt von vorzustellen, an densomefile
sie übergeben wirdsed
. Das Leerzeichen, das die geschweiften Klammern von sich aus trennt, ist hier wichtig, ebenso wie das Semikolon vor der schließenden geschweiften Klammer.1{h;d;};
wie einsed
Befehl , um die erste Zeile des Texts in gespeichert werdensed
‚s Halteraum , dannd
ÉLETE die Linie (statt sie zu drucken)./KEYWORD/
wendet die folgenden Aktionen auf alle Zeilen an, die enthaltenKEYWORD
. Die Aktion istg
et, bei der der Inhalt des Haltebereichs abgerufen und anstelle des Musterbereichs abgelegt wird - mit anderen Worten, die gesamte aktuelle Zeile. (Dies dient nicht zum Ersetzen nur eines Teils einer Zeile.) Der Haltebereich wird übrigens nicht geleert, sondern nur in den Musterbereich kopiert und ersetzt, was auch immer vorhanden ist.Wenn Sie Ihren regulären Ausdruck so verankern möchten, dass er nicht mit einer Zeile übereinstimmt, die lediglich KEYWORD enthält, sondern nur mit einer Zeile, in der sich nichts anderes als KEYWORD befindet, fügen Sie einen Zeilenanker (
^
) und ein Zeilenende ($
) hinzu Ihre Regex:quelle
Mithilfe der Erweiterung der Musterersetzungsparameter von Bash können Sie die Schrägstriche in Ihrer Ersatzzeichenfolge mit einem umgekehrten Schrägstrich umgehen. Es ist ein wenig chaotisch, weil die Schrägstriche auch für Bash entkommen müssen.
Ausgabe
Sie können die Parametererweiterung direkt in Ihren sed-Befehl einfügen:
aber ich denke, die erste Form ist etwas besser lesbar. Und wenn Sie dasselbe Ersetzungsmuster in mehreren sed-Befehlen wiederverwenden möchten, ist es natürlich sinnvoll, die Konvertierung nur einmal durchzuführen.
Eine andere Möglichkeit wäre, ein in awk, perl oder Python geschriebenes Skript oder ein C-Programm zu verwenden, um Ihre Ersetzungen vorzunehmen, anstatt sed zu verwenden.
Hier ist ein einfaches Beispiel in Python, das funktioniert, wenn das zu ersetzende Schlüsselwort eine vollständige Zeile in der Eingabedatei ist (ohne die neue Zeile). Wie Sie sehen können, ist es im Wesentlichen der gleiche Algorithmus wie in Ihrem Bash-Beispiel, aber es liest die Eingabedatei effizienter.
quelle
\x
Fluchtsequenzen im Stil umzuwandeln . Oder um ein Programm zu verwenden, das willkürliche Eingaben verarbeiten kann, wie ich in meinem letzten Absatz erwähnt habe.So bin ich gegangen:
Dies funktioniert in meinem Fall hervorragend, da sich mein Keyword in einer eigenen Zeile befindet. Wenn sich das Schlüsselwort in einer Zeile mit einem anderen Text befindet, funktioniert dies nicht.
Ich würde immer noch gerne wissen, ob es einen einfachen Weg gibt, ohne meine eigene Lösung zu codieren.
quelle
echo
. Verwenden Sieprintf
stattdessen. Und Textverarbeitung in einer Shell-Schleife ist eine schlechte Idee.read
ist ziemlich langsam. Es ist für die Verarbeitung interaktiver Benutzereingaben gedacht, nicht für die Verarbeitung von Textdateien. Es ist langsam, weil es stdin char by char liest und für jedes char einen Systemaufruf ausführt.printf "hi\n"
Mit printf wird eine neue Zeile gedruckt, währendecho "hi\n"
sie so gedruckt wird, wie sie ist.printf
steht für "Format" - das erste Argument dafürprintf
ist ein Formatbezeichner . Wenn dieser Bezeichner ist%s\n
, was bedeutet , „string durch Newline gefolgt“, nichts in die nächste Argument wird durch interpretiert oder übersetzt werdenprintf
überhaupt . (Die Shell kann es natürlich immer noch interpretieren. Halten Sie alles am besten in einfache Anführungszeichen, wenn es sich um eine Literalzeichenfolge handelt, oder in doppelte Anführungszeichen, wenn Sie eine variable Erweiterung wünschen.) Weitere Informationen finden Sie in meiner Antwort unter Verwendungprintf
von.