web-dev-qa-db-ja.com

bashスクリプトを使用してテンプレートから新しいファイルを作成します

Confファイルとinit.dを作成する必要がありますが、これらは非常に似ています。これらのファイルにより、サーバーに新しいhttpサービスをデプロイできます。これらのファイルは同じで、一部のパラメーターのみがファイル間で変更されます(listen_port、ドメイン、サーバー上のパス...)。

これらのファイルにエラーがあるとサービスが誤動作するため、bashスクリプトを使用してこれらのファイルを作成したいと思います。

例えば:

generate_new_http_service.sh 8282 subdomain.domain.com /home/myapp/rootOfHTTPService

Bashで使用できるテンプレートモジュールを探しています。このテンプレートモジュールは、いくつかの汎用confおよびinit.dスクリプトを使用して新しいスクリプトを作成します。

そのためのヒントはありますか?そうでない場合は、pythonテンプレートエンジンを使用できます。

45
iwalktheline

これは、ヒアドキュメントを使用して行うことができます。例えば.

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

出力:

$ generate.sh 8080 domain.com

This is my template.
Port is 8080
Domain is domain.com

またはファイルに保存します:

$ generate.sh 8080 domain.com > result
72
dogbane

Bashのテンプレートモジュールですか? sed、ルークを使用してください!これは、何百万通りの方法のうちの1つの例です。

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

これをbashで直接行うことができ、sedも必要ありません。そのようなスクリプトを作成します。

#!/bin/bash

cat <<END
this is a template
with $foo
and $bar
END

次のように呼び出します:

foo=FOO bar=BAR ./template 
21
Kim Stebel

単純なファイル生成の場合、基本的には

 . "${config_file}"
 template_str=$(cat "${template_file}")
 eval "echo \"${template_str}\""

十分でしょう。

ここに ${config_file}には、シェルで解析可能な形式の構成変数が含まれ、${template_file}は、シェルヒアドキュメントのようなテンプレートファイルです。ファイルの最初の行ソース${config_file}、2行目はファイルの内容${template_file}シェル変数template_str。最後の3行目では、シェルコマンドecho "${template_str}"(二重引用符で囲まれた式"${template_str}"が展開されます)、評価します。

これらの2つのファイルの内容の例については、 https://serverfault.com/a/699377/120756 を参照してください。

テンプレートファイルに含めることができる制限や、シェルのエスケープを実行する必要がある制限があります。また、テンプレートファイルが外部で作成される場合、セキュリティ上の理由から、実行前に適切なフィルタリングの実装を検討する必要があります。たとえば、誰かがテンプレートファイルに有名な$(rm -rf /)を挿入したときにファイルを失うことはありません。

11
FooF

この問題を解決するために私が取ったアプローチは次のとおりです。上記のアプローチのいくつかよりも少し柔軟性があり、引用の問題のいくつかを回避できます。

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"

テンプレート:

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"

結果:重要なものでいっぱいのテンプレート

"Note that quoted "values work too!" are handled correctly"

If I need those
nifty
linebreaks then I can add them as well.
5
Keegs

[編集]数年前の元の回答から変更しました。

上記のFooFからの回答が好きです: https://stackoverflow.com/a/30872526/353817

それでも、テンプレートファイルのコンテンツ全体をメモリに保存するための中間変数を持たないことを好みます。

. "${config_file}"
eval "echo \"$(cat "${template_file}")\""

テンプレートファイルを作成します。それをexample.tplと呼びましょう:

Hello, ${NAME}!
Today, the weather is ${WEATHER}. Enjoy!

変数を保存する構成ファイルを作成します。それをgood.confと呼びましょう:

NAME=John
WEATHER=good

次に、テンプレートをレンダリングするスクリプトで、次のように記述できます。

#!/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

この素晴らしい出力が表示されるはずです:)

Hello, John!
Today, the weather is good. Enjoy!

evalに関する注意

evalを使用する場合、テンプレートファイルに命令が含まれていると、それらの命令が実行され、危険な場合があります。たとえば、上記のexample.tplを次のコンテンツで変更しましょう。

Hello, ${NAME}!
Today, the weather is ${WEATHER}. Enjoy!

I'm a hacker, hu hu! Look, fool!
$(ls /)

これで、テンプレートファイルをレンダリングすると、次のように表示されます。

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

ファイルgood.confを編集して、次のコンテンツを作成します。

NAME=$(ls -l /var)
WEATHER=good

テンプレートをレンダリングします。次のようなものが表示されるはずです。

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

ご覧のとおり、設定ファイルおよびテンプレートファイルが可能です。そのため、特に注意する必要があります。

  • テンプレートファイルの内容を確認してください:コマンドインジェクションがないことを確認してください。
  • 設定ファイルの内容を確認してください:コマンドインジェクションも行われていないことを確認してください。構成ファイルが他の人からのものである場合、テンプレートをレンダリングする前に、その人を知って信頼する必要があります。

あなたがパスワードのないsudoerであり、テンプレートファイルをレンダリングすると、適切に配置されたrm -rfでシステムが台無しになる可能性があると想像してください。

これらのファイルのコンテンツを制御する限り、このevalテンプレートを使用しても構いません。

外部(信頼されていない)着信構成ファイルがある場合は、テンプレートエンジンを探す必要があります。これにより、この種のインジェクションが分離されます。たとえば、Jinja2 templatingはPythonで非常に有名です。

3
Samuel Phan

Perlを使用した1行の簡潔で短いソリューション

Perlを使用して、変数をその値に置き換えます。

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

出力: I love you, World! You are wonderful

my_template.txtには、接頭辞として$

1
kyb

python class string.Template

$ echo 'before $X after' > template.txt

$ python  -c 'import string; print(string.Template(open("template.txt").read()).substitute({"X":"A"}))'

before A after

または

$  python  -c 'import string, sys; print(string.Template(open("template.txt").read()).substitute({"X":sys.argv[1]}))' "A"

ここに $Xはテンプレートのプレースホルダーであり、{"X":"A"}は、プレースホルダーから値へのマッピングです。 pythonコードで、ファイルからテンプレートテキストを読み取り、そこからテンプレートを作成し、プレースホルダーをコマンドライン引数に置き換えます。

または、Rubyがマシンにインストールされている場合、RubyのERBを使用できます。

$ echo "before <%= ENV['X'] %> after" > template.txt

$ X=A erb template.txt

before A after

ここに <%= ENV['X'] %>はプレースホルダーです。 ENV['X']は、環境変数から値を読み取ります。 X=Aは、環境変数を目的の値に設定します。

0
Alexey

私は最近、ジンジャのようなテンプレート構文を使用してまさにそれを達成するbashプロジェクトを公開しました。 cookie と呼ばれます。デモは次のとおりです。

cookie demo

0
Bryan Bugyi