web-dev-qa-db-ger.com

Neue Datei aus Vorlagen mit Bash-Skript erstellen

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.

43
iwalktheline

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
67
dogbane

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
$ 
40
user405725

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 
20
Kim Stebel

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.

10
FooF

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.
5
Keegs

Elegante und kurze Lösung in einer Linie mit 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.

1
kyb

[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}")\""

Beispiel

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!

Vorsicht bei 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:

  • Der Inhalt der Vorlagendatei muss sicher sein: Vergewissern Sie sich, dass KEINE Befehlsinjektion vorliegt.
  • Vergewissern Sie sich, dass der Inhalt der Konfigurationsdatei vorhanden ist: Überprüfen Sie, ob auch KEINE Befehlsinjektion vorliegt. Wenn die Konfigurationsdatei von einer anderen Person stammt, müssen Sie diese Person kennen und vertrauen, bevor Sie die Vorlage rendern.

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.

1
Samuel Phan

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.

0
Alexey

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:

 cookie demo

0
Bryan Bugyi