web-dev-qa-db-ja.com

シェルスクリプトでLinuxをテンプレート化しますか?

私が達成したいのは:

1.)$ version $ path(Apache configなど)などの変数を使用して、設定ファイルをテンプレートとして使用する

2.)テンプレートの変数を「入力」し、生成されたファイルをディスクに書き込むシェルスクリプトを用意します。

これはシェルスクリプトで可能ですか。私がこれを達成できるいくつかのコマンド/ツールまたはいくつかの優れたリンクを挙げていただければ幸いです。

29
Markus

これは非常に可能です。これを実装する非常に簡単な方法は、テンプレートファイルを実際にスクリプトにして、次のようなシェル変数を使用することです。

#! /bin/bash
version="1.2.3"
path="/foo/bar/baz"
cat > /tmp/destfile <<-EOF
here is some config for version $version which should
also reference this path $path
EOF

version=$1path=$2を指定することで、コマンドラインでこれを構成可能にして、bash script /foo/bar/baz 1.2.3のように実行することもできます。 EOFの前の-は、行が無視される前に空白文字を発生させます。その動作を望まない場合は、プレーンな<<EOFを使用してください。

これを行う別の方法は、sedの検索および置換機能を使用することです。

#! /bin/bash
version="1.2.3"
path="/foo/bar/baz"
sed -e "s/VERSION/$version/g" -e "s/PATH/$path/" /path/to/templatefile > /tmp/destfile

文字列VERSIONとPATHの各インスタンスを置き換えます。他の理由でこれらの文字列がテンプレートファイルに含まれる場合は、検索を実行して次のように置き換えます[〜#〜] version [〜#〜]または%VERSION%またはトリガーされる可能性が低いもの偶然。

24
mtinberg

/bin/sh以外のツールは必要ありません。次の形式のテンプレートファイルがあるとします。

Version: ${version}
Path: ${path}

または含まれている混合シェルコードでも

Version: ${version}
Path: ${path}
Cost: ${cost}\$
$(i=1; for w in one two three four; do echo Param${i}: ${w}; i=$(expr $i + 1); done)

とシェルの解析可能な構成ファイルのような

version="1.2.3-r42"
path="/some/place/under/the/Rainbow/where/files/dance/in/happiness"
cost="42"

これを拡張するのは簡単なことです

Version: 1.2.3-r42
Path: /some/place/under/the/Rainbow/where/files/dance/in/happiness
Cost: 42$
Param1: one
Param2: two
Param3: three
Param4: four

実際、シェル変数config_fileの構成ファイルへのパスとtemplate_fileのテンプレートファイルへのパスを指定すると、次のことを行うだけです。

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

これは、テンプレートファイルとして完全なシェルスクリプトを使用するよりも、おそらくかわいそうです(@mtinbergのソリューション)。

完全な単純なテンプレートエキスパンダープログラム:

#!/bin/sh

PROG=$(basename $0)

usage()
{
    echo "${PROG} <template-file> [ <config-file> ]"
}

expand()
{
    local template="$(cat $1)"
    eval "echo \"${template}\""
}

case $# in
    1) expand "$1";;
    2) . "$2"; expand "$1";;
    *) usage; exit 0;;
esac

これにより、拡張が標準出力に出力されます。標準出力をファイルにリダイレクトするか、上記を明白な方法で変更して、目的の出力ファイルを生成します。

警告:ファイルにエスケープされていない二重引用符(")が含まれている場合、テンプレートファイルの展開は機能しません。セキュリティ上の理由から、おそらくいくつかの明確な健全性チェックを含めるか、テンプレートファイルが外部エンティティによって生成された場合はシェルエスケープ変換を実行することをお勧めします。

19
FooF

これをLinux CLIで簡単に行う最も簡単な方法は、envsubstおよび環境変数を使用することです。

テンプレートファイルの例Apache.tmpl

<VirtualHost *:${PORT}>
    ServerName ${SERVER_NAME}
    ServerAlias ${SERVER_ALIAS}
    DocumentRoot "${DOCUMENT_ROOT}"
</VirtualHost>

envsubstを実行し、結果を新しいファイルに出力my_Apache_site.conf

export PORT="443"
export SERVER_NAME="example.com"
export SERVER_ALIAS="www.example.com"
export DOCUMENT_ROOT="/var/www/html/"
envsubst < Apache.tmpl > my_Apache_site.conf

出力:

<VirtualHost *:443>
    ServerName example.com
    ServerAlias www.example.com
    DocumentRoot "/var/www/html/"
</VirtualHost>
14
Lirt

そのために shtpl を使用します。 (私のプライベートプロジェクト。つまり、広く使用されていません。でも、とにかくテストしたいかもしれません。)

たとえば、csvファイルから/ etc/network/interfacesを生成するには、次のようにします。

CSVファイルの内容(ここではtest.csv):

eth0;10.1.0.10;255.255.0.0;10.1.0.1
eth1;192.168.0.10; 255.255.255.0;192.168.0.1

テンプレート(ここではinterfaces.tpl):

#% IFS=';'
#% while read "Val1" "Val2" "Val3" "Val4"; do
auto $Val1 
iface $Val1 inet static
  address $Val2 
  netmask $Val3 
  gateway $Val4 

#% done < "$CSVFILE"

コマンド:

$ CSVFILE=test.csv sh -c "$( shtpl interfaces.tpl )"

結果:

auto eth0 
iface eth0 inet static
  address 10.1.0.10 
  netmask 255.255.0.0 
  gateway 10.1.0.1 

auto eth1 
iface eth1 inet static
  address 192.168.0.10 
  netmask  255.255.255.0 
  gateway 192.168.0.1

楽しい!

4
zstegi

おそらく Puppet または Chef のような構成管理システムを調べる必要があります。これらは上で説明したことを簡単に実行でき、muchより多くのことを実行できます。

4
EEAA

新しいファイルを生成するシェルコードではなく、軽量で実際のテンプレートが必要な場合、通常の選択肢はsedawkまたはPerlです。これが1つのリンクです: http://savvyadmin.com/generate-text-from-templates-scripts-and-csv-data/

私、Perl、tcl、python、Rubyまたはそのクラスの他の何かなどの実際の言語を使用します。スクリプト用に構築されたものです。それらはすべて、優れたシンプルなテンプレートツールと多数の例を備えていますグーグルで。

4
Mark

ユーザーが二重引用符を手動でアンエスケープする必要がないように、FooFの回答を改善しました。

#!/bin/bash
template="$(cat $1)"
template=$(sed 's/\([^\\]\)"/\1\\"/g; s/^"/\\"/g' <<< "$template")
eval "echo \"${template}\""
2
Shaohua Li

私は最近、ジンジャのようなテンプレート構文を使用してそれを実現するbashスクリプトを公開しました。 cookie と呼ばれます。ここにデモがあります:

cookie demo

1
Bryan Bugyi

私はおそらくこのパーティーに遅れます。しかし、私は同じ問題に出くわし、数行のコードで独自のBASHテンプレートエンジンを作成することにしました。

あなたがこれを持っているとしましょうfile.template

# My template
## Author
 - @NAME@ <@EMAIL@>

そして、このrulesファイル:

NAME=LEOPOLDO WINSTON
EMAIL=leothewinston\@leoserver.com

次のコマンドを実行します。

templater rules < file.template

あなたはこれを手に入れます:

# My template
## Author
 - LEOPOLDO WINSTON <[email protected]>

次の方法でインストールできます。

 bpkg install vicentebolea/bash-templater

これはプロジェクトです サイト

0
Vicente Bolea

ヒアドキュメント+制御文字を使用して@FooFの素晴らしい答え(改行がコメントでフォーマットされなかった)を拡張するには、任意の文字を許可できますandファイル名:

_template() {
    # if [ "$#" -eq 0 ] ; then return; fi # or just error
    eval "cat <<$(printf '\x04\x04\x04');
$(cat $1)
"
}
_

これは、null以外の文字を受け入れ、3つの_^D_バイトが自分の行で検出された場合にのみ早期に切り捨てます(実際には決してありません)。 zshはnullターミネーターもサポートしているため、_printf '\x00\x00\x00'_が機能します。 templateは、次のような危険なファイル名でも機能します。

_for num in `seq 10`; do
    template 'foo "$ .html' # works
done
_

シェルテンプレートは、任意のコマンドを「展開」できることに注意してください。 $(launch_nukes.sh --target $(curl -sL https://freegeoip.app/csv/ | cut -d, -f 9,10))。大きな力で…

編集:ファイルに核を起動したくない場合は、事前に_Sudo -u nobody sh_(または他の安全なユーザー)を使用してください。

0
alexchandel