シェルスクリプトでのLinuxのテンプレート?


26

私が達成したいことは:

1.)$ version $ pathなどの変数を使用したテンプレートとしての構成ファイル(たとえば、apache config)

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

これはシェルスクリプトで可能ですか?私がこれまたはいくつかの良いリンクを達成できるいくつかのコマンド/ツールに名前を付けることができれば、私は非常に感謝します。

回答:


23

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

#! /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=$1and を指定することでpath=$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%にしたり、誤ってトリガーされる可能性が低いものにしたりできます。


18

以外のツールは必要ありません/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

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

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


1
このような楽しいことをするためにシェルスクリプトを積極的に使用している人々を見るのは素晴らしいことです。私の相棒がシェルスクリプトで時計を書いた。 github.com/tablespoon/fun/blob/master/cli-clock本当に 楽しい時間です。

2
私はこれを自分で行うことを探して、この答えを見つけたとき、私はかなり単純なアプローチを実装し、GitHubの上でそれを投稿:github.com/nealian/bash-unsafe-templates
Pyrocater

9

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>

2
GNU gettextの一部であるため、Microsoft Windowsだけでなく、すべての主要なUnixプラットフォーム(macOS Xを含む)で利用できます。
トリカス

4

おそらくPuppetChefなどの構成管理システムを検討する必要があります。これらは、あなたが上記で説明したことをはるかに簡単に行うことができます。


1
ありがとう。絶対に、Chefをインストールして実行しています。ただし、独自のクックブックを作成する必要がある場合は、多くのオーバーヘッドが追加されます。私はルビープログラミング言語を知らず、私の結論はそうでした。簡単な場合(可能であれば)のシェルスクリプトを使用してこれを行うのが簡単です。
マーカス

PuppetChefはどちらもテンプレートにERBを使用しているように見えますが、これは非常に簡単に開始できます。変数nameを指定する<%= name %>と、テンプレート内の文字列はnameの値に置き換えられます。nameテンプレートの外部での定義方法は、明らかに2つのシステムで異なります。
マイクレンフロ

1
はい、テンプレートの作成(Chefを使用)自体は非常に簡単です。しかし、フレームワークとしてシェフを使用する(およびクックブックを作成する)には多くの時間が必要です。データをテンプレートに取り込むには、Chefがデータソースや他の多くのものの「マージ」を管理する場所と方法を理解する必要があります。私は自分の料理本を書き始めましたが、シェルスクリプトは私の特別な場合には100倍高速になります
Markus

インフラストラクチャをChefまたはPuppetに移行するのは苦痛かもしれませんし、それらをヘッドレスで実行する方法を見つけようとすることもできます。これは楽しい冒険です。Ansibleは、そのままの状態でプルモードまたはプッシュモードで正常に動作するため、自分で考え出すこととスクリプトを作成することのバランスがとれる可能性があります。 docs.ansible.com/template_module.html

4

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

私は、そのクラスでperl、tcl、python、rubyなどの実際の言語を使用します。スクリプト用に構築されたもの。彼らは皆、グーグルで良い、シンプルなテンプレートツールとたくさんの例を持っています。


4

そのために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

楽しい!


1

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

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

1

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

クッキーデモ


これは質問にどのように答えますか?
-RalfFriedl

1
@RalfFriedlどういう意味かわかりません。私は何かを見逃したに違いないと思って質問を読み直しましたが、見ていません。実際、これは、尋ねられた質問のどの部分に答えないのでしょうか?この質問に答えるという目的だけでクッキーを作ったようなものです...私はそれをやったのですが、当時は頭の中で少し違った言い方をしたかもしれません。:)
ブライアンブギー

私は調停者を演じるのに少し遅れていますが、おそらくラルフはあなたが自分のプロジェクトを知らないことを誰かの問題を解決するかどうかを判断するのを十分に慈善的に示唆するのではなく、単にクッキーが質問にどのように答えるかを説明するようにあなたに促していました。
アバサー

0

私はおそらくこのパーティーに遅れています。しかし、私はまったく同じ問題につまずき、数行のコードで独自の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 <leothewinston@leoserver.com>

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

 bpkg install vicentebolea/bash-templater

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


0

ヒアドキュメント+制御文字を使用して、@ FooFの優れた答え(改行はコメントにフォーマットされませんでした)を拡張するために、任意の文字ファイル名を許可できます。

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

これはヌル以外の文字を受け入れ^D、独自の行で3 バイトが検出された場合にのみ早期に切り捨てます(現実的にはありません)。zshはヌルターミネータもサポートしているため、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(または他の安全なユーザーに)事前にファイルを起動したくない場合。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.