Ich muss Conf-Dateien und init.d
erstellen, die sehr ähnlich sind. Diese Dateien ermöglichen die Bereitstellung eines neuen http-Dienstes auf meinen Servern. Diese Dateien sind gleich und nur einige Parameter ändern sich von Datei zu Datei (listen_port
, Domäne, Pfad auf dem Server ...).
Da jeder Fehler in diesen Dateien zu einer Fehlfunktion des Dienstes führt, möchte ich diese Dateien mit einem Bash-Skript erstellen.
Zum Beispiel:
generate_new_http_service.sh 8282 subdomain.domain.com /home/myapp/rootOfHTTPService
Ich suche nach einer Art Template-Modul, das ich mit Bash verwenden könnte. Dieses Vorlagenmodul würde einige generische conf- und init.d-Skripts verwenden, um neue zu erstellen.
Hast du Hinweise dazu? Wenn nicht, könnte ich Python Templating Engine verwenden.
Sie können dies mit einem Heredoc tun. z.B.
generate.sh:
#!/bin/sh
#define parameters which are passed in.
PORT=$1
DOMAIN=$2
#define the template.
cat << EOF
This is my template.
Port is $PORT
Domain is $DOMAIN
EOF
Ausgabe:
$ generate.sh 8080 domain.com
This is my template.
Port is 8080
Domain is domain.com
oder speichern Sie es in einer Datei:
$ generate.sh 8080 domain.com > result
Vorlagenmodul für bash? Verwenden Sie sed
, Luke! Hier ist ein Beispiel für eine von Millionen möglichen Möglichkeiten, dies zu tun:
$ cat template.txt
#!/bin/sh
echo Hello, I am a server running from %DIR% and listening for connection at %Host% on port %PORT% and my configuration file is %DIR%/server.conf
$ cat create.sh
#!/bin/sh
sed -e "s;%PORT%;$1;g" -e "s;%Host%;$2;g" -e "s;%DIR%;$3;g" template.txt > script.sh
$ bash ./create.sh 1986 example.com /tmp
$ bash ./script.sh
Hello, I am a server running from /tmp and listening for connection at example.com on port 1986 and my configuration file is /tmp/server.conf
$
sie können dies direkt in der bash tun, Sie brauchen nicht einmal sed. Schreibe so ein Skript:
#!/bin/bash
cat <<END
this is a template
with $foo
and $bar
END
dann nennen Sie es so:
foo=FOO bar=BAR ./template
Für die einfache Erzeugung von Dateien
. "${config_file}"
template_str=$(cat "${template_file}")
eval "echo \"${template_str}\""
würde genügen.
Hier enthält ${config_file}
die Konfigurationsvariablen im parsbaren Format von Shell, und ${template_file}
ist die Vorlagendatei, die wie ein Shell-Dokument aussieht. Die erste Zeilenquelle in der Datei ${config_file}
, die zweite Zeile fügt den Inhalt der Datei ${template_file}
in die Shell-Variable template_str
ein. In der dritten Zeile schließlich erstellen wir den Shell-Befehl echo "${template_str}"
(wobei der doppelte Anführungszeichen-Ausdruck "${template_str}"
erweitert wird) und werten ihn aus.
Ein Beispiel für den Inhalt dieser beiden Dateien finden Sie unter https://serverfault.com/a/699377/120756 .
In der Vorlagendatei gibt es Einschränkungen, oder Sie müssen eine Shell-Escape-Aktion ausführen. Wenn die Vorlagendatei extern erstellt wird, müssen Sie aus Sicherheitsgründen vor der Ausführung eine geeignete Filterung implementieren, damit Sie beispielsweise nicht Ihre Dateien verlieren, wenn jemand die berühmte $(rm -rf /)
in die Vorlagendatei einfügt.
Hier ist der Ansatz, den ich am Ende genommen habe, um dieses Problem zu lösen. Ich fand es etwas flexibler als einige der oben genannten Ansätze und vermeidet einige Probleme mit Zitaten.
fill.sh:
#!/usr/bin/env sh
config="$1"
template="$2"
destination="$3"
cp "$template" "$destination"
while read line; do
setting="$( echo "$line" | cut -d '=' -f 1 )"
value="$( echo "$line" | cut -d '=' -f 2- )"
sed -i -e "s;%${setting}%;${value};g" "$destination"
done < "$config"
Vorlage:
Template full of important %THINGS%
"Note that quoted %FIELDS% are handled correctly"
If I need %NEWLINES% then I can add them as well.
config:
THINGS=stuff
FIELDS="values work too!"
NEWLINES="those\\nnifty\\nlinebreaks"
Ergebnis: Vorlage voller wichtiger Sachen
"Note that quoted "values work too!" are handled correctly"
If I need those
nifty
linebreaks then I can add them as well.
Perl
Ich verwende Perl
, um Variablen durch ihre Werte zu ersetzen:
export world=World beautiful=wonderful
echo 'I love you, $world! You are $beautiful.' >my_template.txt
Perl -pe 's|\$([A-Za-z_]+)|$ENV{$1}|g' my_template.txt
Die Ausgabe: I love you, World! You are wonderful
.
my_template.txt
kann Variablen enthalten, denen $
vorangestellt ist.
[Bearbeiten] Ich habe meine Antwort von der ursprünglichen, vor Jahren, geändert.}
Ich mag die Antwort von FooF oben: https://stackoverflow.com/a/30872526/3538173
Ich ziehe es jedoch vor, keine Zwischenvariable zu haben, um den gesamten Inhalt der Vorlagendatei im Speicher zu speichern.
. "${config_file}"
eval "echo \"$(cat "${template_file}")\""
Erstellen Sie eine Vorlagendatei. Nennen wir es example.tpl
:
Hello, ${NAME}!
Today, the weather is ${WEATHER}. Enjoy!
Erstellen Sie eine Konfigurationsdatei zum Speichern Ihrer Variablen. Nennen wir es good.conf
:
NAME=John
WEATHER=good
In dem Skript, in dem Sie die Vorlage rendern möchten, können Sie Folgendes schreiben:
#!/usr/bin/env bash
template_file=example.tpl
config_file=good.conf
. "${config_file}"
eval "echo \"$(cat "${template_file}")\""
# Or store the output in a file
eval "echo \"$(cat "${template_file}")\"" > out
Sie sollten diese wunderbare Ausgabe sehen :)
Hello, John!
Today, the weather is good. Enjoy!
eval
Wenn Sie eval
verwenden und die Vorlagendatei Anweisungen enthält, werden diese ausgeführt und können gefährlich sein. Ändern wir beispielsweise den example.tpl
mit diesem Inhalt:
Hello, ${NAME}!
Today, the weather is ${WEATHER}. Enjoy!
I'm a hacker, hu hu! Look, fool!
$(ls /)
Wenn Sie nun Ihre Vorlagendatei rendern, sehen Sie Folgendes:
Hello, John!
Today, the weather is good. Enjoy!
I'm a hacker, hu hu! Look, fool!
bin
boot
dev
etc
home
lib
lib64
media
mnt
opt
proc
root
run
sbin
srv
sys
tmp
usr
var
Bearbeiten Sie nun Ihre Datei good.conf
, um folgenden Inhalt zu erhalten:
NAME=$(ls -l /var)
WEATHER=good
und rendern Sie die Vorlage. Sie sollten so etwas sehen:
Hello, total 8
drwxr-xr-x. 2 root root 6 Apr 11 04:59 adm
drwxr-xr-x. 5 root root 44 Sep 11 18:04 cache
drwxr-xr-x. 3 root root 34 Sep 11 18:04 db
drwxr-xr-x. 3 root root 18 Sep 11 18:04 empty
drwxr-xr-x. 2 root root 6 Apr 11 04:59 games
drwxr-xr-x. 2 root root 6 Apr 11 04:59 Gopher
drwxr-xr-x. 3 root root 18 May 9 13:48 kerberos
drwxr-xr-x. 28 root root 4096 Oct 8 00:30 lib
drwxr-xr-x. 2 root root 6 Apr 11 04:59 local
lrwxrwxrwx. 1 root root 11 Sep 11 18:03 lock -> ../run/lock
drwxr-xr-x. 8 root root 4096 Oct 8 04:55 log
lrwxrwxrwx. 1 root root 10 Sep 11 18:03 mail -> spool/mail
drwxr-xr-x. 2 root root 6 Apr 11 04:59 nis
drwxr-xr-x. 2 root root 6 Apr 11 04:59 opt
drwxr-xr-x. 2 root root 6 Apr 11 04:59 preserve
lrwxrwxrwx. 1 root root 6 Sep 11 18:03 run -> ../run
drwxr-xr-x. 8 root root 87 Sep 11 18:04 spool
drwxrwxrwt. 4 root root 111 Oct 9 09:02 tmp
drwxr-xr-x. 2 root root 6 Apr 11 04:59 yp!
Today, the weather is good. Enjoy!
I'm a hacker, hu hu! Look, fool!
bin
boot
dev
etc
home
lib
lib64
media
mnt
opt
proc
root
run
sbin
srv
swapfile
sys
tmp
usr
var
Wie Sie sehen, ist die Befehlseingabe in die Konfigurationsdatei Konfigurationsdatei und die Vorlagendatei möglich. Deshalb müssen Sie besonders vorsichtig sein:
Stellen Sie sich vor, Sie sind ein passwortloses Sudoer. Das Rendern der Vorlagendatei kann dazu führen, dass Ihr System durch einen gut platzierten rm -rf
zerstört wird.
Solange Sie den Inhalt dieser Dateien steuern, können Sie diese eval
-Vorlage verwenden.
Wenn Sie über eine externe (nicht vertrauenswürdige) eingehende Konfigurationsdatei verfügen, sollten Sie nach einer Vorlage suchen, die diese Art der Injektion isoliert. Zum Beispiel ist Jinja2 Templating in Python ziemlich berühmt.
Sie können die Python-Klasse string.Template
verwenden.
$ echo 'before $X after' > template.txt
$ python -c 'import string; print(string.Template(open("template.txt").read()).substitute({"X":"A"}))'
before A after
oder
$ python -c 'import string, sys; print(string.Template(open("template.txt").read()).substitute({"X":sys.argv[1]}))' "A"
Hier ist $X
ein Platzhalter in der Vorlage und {"X":"A"}
eine Zuordnung des Platzhalters zu einem Wert. Im Python-Code lesen wir den Vorlagentext aus der Datei, erstellen daraus eine Vorlage und ersetzen dann den Platzhalter durch das Befehlszeilenargument.
Alternativ können Sie Ruby's ERB verwenden, wenn Ruby auf Ihrem Computer installiert ist.
$ echo "before <%= ENV['X'] %> after" > template.txt
$ X=A erb template.txt
before A after
Hier ist <%= ENV['X'] %>
ein Platzhalter. ENV['X']
liest den Wert aus der Umgebungsvariablen. X=A
setzt die Umgebungsvariable auf den gewünschten Wert.
Ich habe vor kurzem ein Bash-Projekt veröffentlicht, das genau dies mit einer Jinja-ähnlichen Vorlagensyntax bewerkstelligt. Es heißt cookie . Hier ist eine Demo: