Ich schreibe ein Skript, um das Erstellen von Konfigurationsdateien für Apache und PHP für meinen eigenen Webserver zu automatisieren. Ich möchte keine GUIs wie CPanel oder ISPConfig verwenden.
Ich habe einige Vorlagen für Apache- und PHP-Konfigurationsdateien. Das Bash-Skript muss Vorlagen lesen, Variablen ersetzen und analysierte Vorlagen in einem Ordner ausgeben. Was ist der beste Weg das zu tun? Ich kann mir verschiedene Möglichkeiten vorstellen. Welches ist das beste oder gibt es vielleicht bessere Möglichkeiten, das zu tun? Ich möchte das in reinem Bash machen (es ist zum Beispiel in PHP einfach)
1) Wie ersetze ich $ {} Platzhalter in einer Textdatei?
template.txt:
the number is ${i}
the word is ${word}
script.sh:
#!/bin/sh
#set variables
i=1
word="dog"
#read in template one line at the time, and replace variables
#(more natural (and efficient) way, thanks to Jonathan Leffler)
while read line
do
eval echo "$line"
done < "./template.txt"
Übrigens, wie leite ich die Ausgabe hier in eine externe Datei um? Muss ich etwas entkommen, wenn Variablen beispielsweise Anführungszeichen enthalten?
2) Verwenden von cat & sed zum Ersetzen jeder Variablen durch ihren Wert:
Gegeben template.txt:
The number is ${i}
The word is ${word}
Befehl:
cat template.txt | sed -e "s/\${i}/1/" | sed -e "s/\${word}/dog/"
Scheint mir schlecht zu sein, weil ich vielen verschiedenen Symbolen entkommen muss und bei vielen Variablen die Zeile zu lang ist.
Können Sie sich eine andere elegante und sichere Lösung vorstellen?
quelle
Antworten:
Sie können dies verwenden:
um alle
${...}
Zeichenfolgen durch entsprechende Umgebungsvariablen zu ersetzen (vergessen Sie nicht, sie zu exportieren, bevor Sie dieses Skript ausführen).Für Pure Bash sollte dies funktionieren (vorausgesetzt, Variablen enthalten keine $ {...} Strings):
. Lösung, die nicht hängt, wenn RHS auf eine Variable verweist, die auf sich selbst verweist:
WARNUNG : Ich kenne keine Möglichkeit, Eingaben mit NULs in Bash korrekt zu verarbeiten oder die Anzahl der nachgestellten Zeilenumbrüche beizubehalten. Die letzte Variante wird so dargestellt, wie sie ist, weil Shells die binäre Eingabe „lieben“:
read
interpretiert Backslashes.read -r
interpretiert keine Backslashes, löscht jedoch die letzte Zeile, wenn sie nicht mit einer neuen Zeile endet."$(…)"
wird so viele nachfolgende Zeilenumbrüche entfernen, wie vorhanden sind, also beende ich…
mit; echo -n a
und verwendeecho -n "${line:0:-1}"
: Dies löscht das letzte Zeichen (das ista
) und behält so viele nachfolgende Zeilenumbrüche bei, wie in der Eingabe vorhanden waren (einschließlich Nein).quelle
[^}]
um[A-Za-Z_][A-Za-z0-9_]
zu verhindern, dass die Shell über die strikte Substitution hinausgeht (z. B. wenn sie versucht, sie zu verarbeiten${some_unused_var-$(rm -rf $HOME)}
).$&
die Perl-Lösung ändern in""
: Erstens bleibt sie${...}
unberührt, wenn sie nicht ersetzt werden kann, und zweitens wird sie durch eine leere Zeichenfolge ersetzt.while
Verwenden Sie die Option, damit die Schleife die letzte Zeile liest, auch wenn sie nicht durch eine neue Zeile abgeschlossen istwhile read -r line || [[ -n $line ]]; do
. Darüber hinaus entfernt Ihrread
Befehl führende und nachfolgende Leerzeichen aus jeder Zeile. Um dies zu vermeiden, verwenden Siewhile IFS= read -r line || [[ -n $line ]]; do
\
Sie sie umgehen).Versuchen
envsubst
quelle
envsubst
ist bei Verwendung eines Heredocs nicht erforderlich, da bash den Heredoc als wörtliche Zeichenfolge in doppelten Anführungszeichen behandelt und bereits darin enthaltene Variablen interpoliert. Es ist jedoch eine gute Wahl, wenn Sie die Vorlage aus einer anderen Datei lesen möchten. Ein guter Ersatz für die viel umständlicherenm4
.envsubst
ist ein GNU-Dienstprogramm gettext und eigentlich gar nicht so robust (da gettext zum Lokalisieren menschlicher Nachrichten gedacht ist). Am wichtigsten ist, dass Backslash-Escape-$ {VAR} -Substitutionen nicht erkannt werden (Sie können also keine Vorlage haben, die zur Laufzeit $ VAR-Substitutionen verwendet, z. B. ein Shell-Skript oder eine Nginx-Conf-Datei). In meiner Antwort finden Sie eine Lösung für Backslash-Escapezeichen.<<"EOF"
, die keine Variablen interpoliert (Anführungszeichen in Anführungszeichen sind wie einfache Anführungszeichen von Heredocs).cat template.txt | envsubst
envsubst war neu für mich. Fantastisch.
Für die Aufzeichnung ist die Verwendung eines Heredoc eine großartige Möglichkeit, eine Conf-Datei zu erstellen.
quelle
envsubst
weil es mich vor dem zusätzlichenapt-get install gettext-base
in meinem Dockerfile gerettet hatIch bin mit der Verwendung von sed einverstanden: Es ist das beste Tool zum Suchen / Ersetzen. Hier ist mein Ansatz:
quelle
-i
Option (Dateien an Ort und Stelle bearbeiten), die der Perl- Option ähnelt . Überprüfen Sie die Manpage für Ihre sed .Ich denke, eval funktioniert wirklich gut. Es verarbeitet Vorlagen mit Zeilenumbrüchen, Leerzeichen und allerlei Bash-Dingen. Wenn Sie die volle Kontrolle über die Vorlagen selbst haben, natürlich:
Diese Methode sollte natürlich mit Vorsicht angewendet werden, da eval beliebigen Code ausführen kann. Dies als root auszuführen kommt so gut wie nicht in Frage. Anführungszeichen in der Vorlage müssen maskiert werden, sonst werden sie von gegessen
eval
.Sie können hier Dokumente verwenden , wenn Sie es vorziehen ,
cat
zuecho
@plockc hat eine Lösung gefunden, die das Problem des Bash-Zitats vermeidet:
Bearbeiten: Teil über das Ausführen als Root mit sudo entfernt ...
Bearbeiten: Kommentar hinzugefügt, wie Anführungszeichen maskiert werden müssen, Plockc-Lösung zum Mix hinzugefügt!
quelle
eval
edecho
/cat
Befehle Prozesse sie; versuche eseval "echo \"'\$HOME'\""
.Ich habe eine Bash-Lösung wie Mogsie, aber mit Heredoc anstelle von Herestring, damit Sie nicht doppelten Anführungszeichen entkommen
quelle
${param:?}
und Verschachtelung von Text um optionale Parameter. Beispiel:${DELAY:+<delay>$DELAY</delay>}
Wird zu nichts erweitert, wenn DELAY undefiniert ist, und <delay> 17 </ Delay>, wenn DELAY = 17 ist._EOF_$$
.$trailing_newline
oder$NL5
diese als 5 Zeilenumbrüche zu erweitern.template.txt
, um funktionieren würde Hinterzeilenumbrüche zu bewahren.eval
, wenntemplate.txt
enthältEOF
auf einer eigenen Zeile, wird es vorzeitig beenden , die hier-doc und damit den Befehl brechen. (Spitze des Hutes zu @xebeche).Bearbeiten 6. Januar 2017
Ich musste doppelte Anführungszeichen in meiner Konfigurationsdatei behalten, damit doppelte Anführungszeichen mit sed helfen:
Ich kann mir nicht vorstellen, neue Zeilen zu verfolgen, aber dazwischen werden leere Zeilen beibehalten.
Obwohl es ein altes Thema ist, fand ich IMO hier eine elegantere Lösung: http://pempek.net/articles/2013/07/08/bash-sh-as-template-engine/
Alle Credits an Grégory Pakosz .
quelle
eval "echo \"$(sed 's/\"/\\"/g' $1)\""
$variables
) vorlegen .Anstatt das Rad neu zu erfinden, gehen Sie mit envsubst Kann in fast jedem Szenario verwendet werden, z. B. zum Konfigurationsdateien aus Umgebungsvariablen in Docker-Containern.
Wenn Sie auf einem Mac sicherstellen, dass Sie Homebrew haben, verknüpfen Sie es mit gettext:
./template.cfg
./.env:
./configure.sh
Jetzt benutze es einfach:
quelle
envsubst
funktioniert tatsächlich.envsubst
funktioniert nicht unter MacOS, müssen Sie es mit Homebrew installieren :brew install gettext
.Eine längere, aber robustere Version der akzeptierten Antwort:
Dies erweitert alle Instanzen von
$VAR
oder${VAR}
auf ihre Umgebungswerte (oder, wenn sie nicht definiert sind, die leere Zeichenfolge).Es entgeht Backslashes ordnungsgemäß und akzeptiert ein $ mit Backslash-Escape, um die Substitution zu verhindern (im Gegensatz zu envsubst, das dies, wie sich herausstellt, nicht tut ).
Also, wenn Ihre Umgebung ist:
und Ihre Vorlage ist:
das Ergebnis wäre:
Wenn Sie Backslashes nur vor $ vermeiden möchten (Sie könnten "C: \ Windows \ System32" unverändert in eine Vorlage schreiben), verwenden Sie diese leicht modifizierte Version:
quelle
Ich hätte es so gemacht, wahrscheinlich weniger effizient, aber einfacher zu lesen / zu warten.
quelle
sed -e 's/VARONE/NEWVALA/g' -e 's/VARTWO/NEWVALB/g' -e 's/VARTHR/NEWVALC/g' < $TEMPLATE > $OUTPUT
Wenn Sie Jinja2- Vorlagen verwenden möchten , sehen Sie sich dieses Projekt an: j2cli .
Es unterstützt:
quelle
Wenn Sie die Antwort von ZyX mit reinem Bash nehmen, aber mit neuem Regex-Matching und indirekter Parametersubstitution, wird es:
quelle
Bei der Verwendung von Perl ist eine Option , und Sie sind zufrieden mit Erweiterungen auf stützen Umwelt nur Variablen (im Gegensatz zu allen gegenüberliegenden Shell - Variablen), betrachten Stuart P. Bentley robuste Antwort .
Diese Antwort zielt darauf ab, eine reine Bash-Lösung bereitzustellen , die trotz Verwendung sicher sein
eval
sollte .Die Ziele sind:
${name}
als auch von$name
variablen Referenzen.$(...)
und Legacy-Syntax`...`
)$((...))
und Legacy-Syntax$[...]
).\
(\${name}
)."
und\
Instanzen.Funktion
expandVars()
:Beispiele:
${HOME:0:10}
, solange sie keinen eingebetteten Befehl oder arithmetische Ersetzungen enthalten, wie z${HOME:0:$(echo 10)}
$(
und`
Instanzen blind maskiert sind).${HOME
(fehlendes Schließen}
) die Funktion.\$name
verhindert Expansion.\
nicht gefolgt$
wird, bleibt unverändert.\
Instanzen darstellen möchten , müssen Sie diese verdoppeln . z.B:\\
->\
- das gleiche wie gerade\
\\\\
->\\
0x1
,0x2
,0x3
.eval
.Wenn Sie nach einer restriktiveren Lösung
${name}
suchen , die nur Erweiterungen unterstützt, dh mit obligatorischen geschweiften Klammern, die$name
Referenzen ignorieren, lesen Sie meine Antwort .Hier ist eine verbesserte Version der Nur-Bash-
eval
freien Lösung aus der akzeptierten Antwort :Die Verbesserungen sind:
${name}
und$name
variablen Referenzen.\
-scaping-Variablenreferenzen, die nicht erweitert werden sollten.eval
obigen Lösung auf Basis vonquelle
Hier ist eine weitere reine Bash-Lösung:
$ cat code
$ cat template
(mit nachgestellten Zeilenumbrüchen und doppelten Anführungszeichen)Ausgabe
quelle
Hier ist eine andere Lösung: Generieren Sie ein Bash-Skript mit allen Variablen und dem Inhalt der Vorlagendatei. Dieses Skript würde folgendermaßen aussehen:
Wenn wir dieses Skript in bash einspeisen, wird die gewünschte Ausgabe erzeugt:
So generieren Sie dieses Skript und geben es in bash ein:
Diskussion
cat
Subshell generieren wir den Befehl mit HEREDOCWenn Sie diese Ausgabe in eine Datei umleiten möchten, ersetzen Sie die letzte Zeile durch:
quelle
Diese Seite beschreibt eine Antwort mit awk
quelle
Perfekter Fall für shtpl . (Projekt von mir, daher ist es nicht weit verbreitet und es fehlt an Dokumentation. Aber hier ist die Lösung, die es trotzdem bietet. Vielleicht möchten Sie es testen.)
Einfach ausführen:
Ergebnis ist:
Habe Spaß.
quelle
Dies ist die reine Bash-Funktion, die nach Ihren Wünschen einstellbar ist, in der Produktion verwendet wird und bei keiner Eingabe unterbrochen werden sollte. Wenn es kaputt geht - lass es mich wissen.
quelle
Sie können auch bashible verwenden (das intern den oben / unten beschriebenen Bewertungsansatz verwendet).
Es gibt ein Beispiel, wie ein HTML aus mehreren Teilen generiert wird:
https://github.com/mig1984/bashible/tree/master/examples/templates
quelle
Hier ist eine Bash-Funktion, die Leerzeichen beibehält:
quelle
Hier ist ein modifiziertes
perl
Skript, das auf einigen der anderen Antworten basiert:Funktionen (basierend auf meinen Anforderungen, sollten aber leicht zu ändern sein):
quelle
Sehen Sie sich hier das Python-Skript zur einfachen Substitution von Variablen an: https://github.com/jeckep/vsubst
Es ist sehr einfach zu bedienen:
quelle
Mein bescheidener Beitrag zu dieser wunderbaren Frage.
Dies funktioniert im Wesentlichen, indem die Subshell zum Ersetzen von Envars verwendet wird, mit der Ausnahme, dass eval nicht verwendet wird und explizite einfache und doppelte Anführungszeichen vermieden werden. Es verkettet die var-Ausdrücke in einer einzigen Zeile ohne zu verwirrende Leerzeichen
sh
und übergibt dann die Vorlage anecho
, sodasssh
die var-Ersetzungen verarbeitet werden können. Es behält Zeilenumbrüche, Kommentare usw. bei und Sie können entkommen,\${like_this}
wenn Sie nicht möchten, dass die Variable interpretiert wird.${missing_var}
wird nur durch einen leeren Wert ersetzt.Viele der anderen Antworten hier sind sehr gut, aber ich wollte etwas sehr Einfaches und es muss nicht buchstäblich jeden möglichen Fall für die Vorlagenfälle behandeln, die ich derzeit habe.
Genießen!
quelle
Um die Antwort von plockc auf dieser Seite weiterzuverfolgen , finden Sie hier eine für das Dash geeignete Version für diejenigen unter Ihnen, die Bashismen vermeiden möchten.
quelle
Einfacher geht es nicht als:
$ person = Bob ./render template.txt> render.txt
Siehe https://github.com/relaxdiego/renderest
quelle