Verwenden von sed in Shell-Skripten mit mehrzeiligen Variablen

Verwenden von sed in Shell-Skripten mit mehrzeiligen Variablen

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 sedmit so deklarierten Variablen zu tun?

Antwort1

Die Standardsyntax für den aBefehl lautet:

sed -e 'a\
first line\
  second line\
last line'

BSD (zumindest FreeBSD und OS/X) sedentfernt die führenden Leerzeichen, Undbenötigt das -eum einen Fehler zu umgehen. GNU sederlaubt 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 -idurch -i ''unter FreeBSD oder OS/X).

Unter GNU/Linux und mit der GNU-Shell ( bash) oder zshkönnen Sie stattdessen Folgendes tun:

sed -i '/MatchingPattern/r /dev/stdin' <<< "$VAR"

Das funktioniert, weil Here-Strings mit gelöschten temporären Dateien bashimplementiert zshwerden 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 inplaceas versucht zunächst, die Erweiterung (as oder ) aus dem aktuellen Arbeitsverzeichnis gawkzu laden , wo jemand Malware platziert haben könnte. Der Pfad der mit gelieferten Erweiterung kann je nach System unterschiedlich sein, siehe die Ausgabe voninplaceinplaceinplace.awkinplacegawkgawk 'BEGIN{print ENVIRON["AWKPATH"]}'

Oder perl(woher das -ikommt):

(export VAR
perl -pi -e '$_ .= "$ENV{VAR}\n" if /MatchingPattern/' somefile)

Antwort2

Der Fehler liegt daran, dass der sedAnfügebefehl anach dem eigentlichen einen Backslash benötigt a:

Mit GNU sed:

$ sed "/pattern/a\\$VAR" file.in >file.out

BSD sedkann, soweit ich weiß, mit dem aBefehl 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

verwandte Informationen