LoginSignup
1
1

More than 3 years have passed since last update.

シェルスクリプトによる超簡易テンプレートエンジン

Last updated at Posted at 2020-09-05

説明

たった4行のシェルスクリプトである。

render_template.sh
#!/bin/sh
sh <<__EOT1__
cat <<__EOT2__
cat "$@"

何一つインストールされていなくて、sh コマンドと cat コマンドだけは動く、そんな環境で使う。
例えば Docker に最適。
コマンドライン引数で指定されたファイル群をヒアドキュメントとして解釈させる。
シェルスクリプトのヒアドキュメントとして展開できるものがすべて通用する。

  • 環境変数展開 ($環境変数名、または${環境変数名})
  • コマンド展開 ($(コマンド)、または`コマンド`)

シェル変数は子プロセスに伝播しないので使えない。export で環境変数にしなければならない。

ヒアドキュメントのため、実行制御機能は持たない。つまり、条件判断、繰り返しなどは行わない。
(コマンド展開による簡易的な条件判断と繰り返しは可能。)

テンプレート側では、ヒアドキュメントで展開対象となる以下の文字群はあらかじめ \(U+005c バックスラッシュ)でエスケープしておく。

  • $ (U+0024)
  • \ (U+005c)
  • ` (U+0060)

ヒアドキュメントの終端に __EOT1__, __EOT2__ が使われているが、確実にファイル内容や変数と衝突しないような文字列を入れればよい。例えば UUID あたりの方がよい。
ファイル終端がヒアドキュメントの終端として扱われるので、実は終端は書かなくてよい。(ここがミソ)

なお、コマンドがネストするのでパフォーマンスはよくない。

本来は #!/bin/sh は要らないはずだが、外すと bash が sh をエミュレートしている環境でヒアドキュメントの終端不足の警告が出てくるので付けている。

./render_template.sh: line 4: warning: here-document at line 2 delimited by end-of-file (wanted `__EOT1__')

仕組み

テンプレートファイル

hello.tmpl
$HELLO

実行

$ HELLO="Hello, world!" ./render_template.sh hello.tmpl

最初の sh に対するヒアドキュメントとして以下が展開される。

before_eval_at_sh
cat <<__EOT2__
`cat "$@"`
after_eval_at_sh
cat <<__EOT2__
$HELLO

次に cat に対するヒアドキュメントとして以下が展開される。

before_eval_at_cat
$HELLO
after_eval_at_cat
Hello, world!

つまり二重にヒアドキュメントを解釈させるところがミソ。

テスト

テンプレートファイル

test.tmpl
Hello, world!
"Hello, world!"
$HELLO
\$HELLO
\\$HELLO
$(echo "Hello, world!")
\$(echo "Hello, world!")
`echo "Hello, world!"`
\`echo "Hello, world!"\`
\\\`echo "Hello, world!"\\\`

実行

$ HELLO="Hello, env!" ./render_template.sh test.tmpl
Hello, world!
"Hello, world!"
Hello, env!
$HELLO
\Hello, env!
Hello, world!
$(echo "Hello, world!")
Hello, world!
`echo "Hello, world!"`
\`echo "Hello, world!"\`

参考

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1