
Ich verwende Shell-Skripte, um verschiedene Arten von VMs einzurichten. Oft enthalten diese Skripte mehrzeilige Variablen, die an bestimmten Stellen in Konfigurationsdateien eingefügt werden müssen sed
.
Wenn ich diese so erstelle, ist alles in Ordnung:
VAR="Config Line1\nConfig Line2\nConfig Line 3"
sed -i "/MatchingPattern/ a $VAR" somefile
Dies beeinträchtigt allerdings die Lesbarkeit des Skripts, insbesondere da die Textblöcke recht lang sein können.
Wenn ich sie so schreibe:
VAR="Config Line1
Config Line2
Config Line 3"
sed -i "/MatchingPattern/ a $VAR" somefile
Beim Ausführen des Skripts wird eine Fehlermeldung angezeigt: sed: -e expression #1, char 31: unknown command:
C'`
Gibt es eine Möglichkeit, dies sed
mit so deklarierten Variablen zu tun?
Antwort1
Die Standardsyntax für den a
Befehl lautet:
sed -e 'a\
first line\
second line\
last line'
BSD (zumindest FreeBSD und OS/X) sed
entfernt die führenden Leerzeichen, Undbenötigt das -e
um einen Fehler zu umgehen. GNU sed
erlaubt das Verschieben der ersten Zeile direkt danach, a\
solange diese nicht leer ist.
Sie müssen die Eingabe also vorverarbeiten:
VAR='content with
multiple lines
some with lead blanks
or even backslash\'
preprocessed_VAR=$(printf '%s\n' "$VAR" |
sed 's/\\/&&/g;s/^[[:blank:]]/\\&/;s/$/\\/')
sed -i -e "/MatchingPattern/a\\
${preprocessed_VAR%?}" somefile
(ersetzen -i
durch -i ''
unter FreeBSD oder OS/X).
Unter GNU/Linux und mit der GNU-Shell ( bash
) oder zsh
können Sie stattdessen Folgendes tun:
sed -i '/MatchingPattern/r /dev/stdin' <<< "$VAR"
Das funktioniert, weil Here-Strings mit gelöschten temporären Dateien bash
implementiert zsh
werden und /dev/stdin unter Linux als symbolischer Link zur Datei implementiert wird (was bedeutet, dass sie mehrmals geöffnet werden kann und jedes Mal von Anfang an geöffnet ist).
Hier könnte man stattdessen auch GNU verwenden awk
:
(export VAR
gawk -i /usr/share/awk/inplace.awk '{print}; /MatchingPattern/{print ENVIRON["VAR"]}' somefile)
Verwende nicht-i inplace
as versucht zunächst, die Erweiterung (as oder ) aus dem aktuellen Arbeitsverzeichnis gawk
zu laden , wo jemand Malware platziert haben könnte. Der Pfad der mit gelieferten Erweiterung kann je nach System unterschiedlich sein, siehe die Ausgabe voninplace
inplace
inplace.awk
inplace
gawk
gawk 'BEGIN{print ENVIRON["AWKPATH"]}'
Oder perl
(woher das -i
kommt):
(export VAR
perl -pi -e '$_ .= "$ENV{VAR}\n" if /MatchingPattern/' somefile)
Antwort2
Der Fehler liegt daran, dass der sed
Anfügebefehl a
nach dem eigentlichen einen Backslash benötigt a
:
Mit GNU sed
:
$ sed "/pattern/a\\$VAR" file.in >file.out
BSD sed
kann, soweit ich weiß, mit dem a
Befehl nur eine einzelne Zeile in eine Datei einfügen, es sei denn, die Zeilenumbrüche werden ordnungsgemäß maskiert.
Eng verwandte Antwort zur Lösung dieses Problems mit BSD sed
:http://unix.stackexchange.com/a/60322