Bashテンプレート:Bashを使用してテンプレートから構成ファイルを構築する方法?


134

私は自分のWebサーバー用のApacheとPHPの構成ファイルの作成を自動化するスクリプトを書いています。CPanelやISPConfigのようなGUIを使いたくありません。

ApacheとPHPの構成ファイルのテンプレートがいくつかあります。Bashスクリプトは、テンプレートを読み取り、変数を置換し、解析されたテンプレートをいくつかのフォルダーに出力する必要があります。それを行う最良の方法は何ですか?私はいくつかの方法を考えることができます。どちらが最高ですか、それを行うにはもっと良い方法がありますか?純粋なBashでそれを実行したい(たとえば、PHPでは簡単です)

1)テキストファイルの$ {}プレースホルダーを置き換える方法は?

template.txt:

the number is ${i}
the word is ${word}

script.sh:

#!/bin/sh

#set variables
i=1
word="dog"
#read in template one line at the time, and replace variables
#(more natural (and efficient) way, thanks to Jonathan Leffler)
while read line
do
    eval echo "$line"
done < "./template.txt"

ところで、ここで外部ファイルに出力をリダイレクトするにはどうすればよいですか?変数に引用符が含まれている場合、何かをエスケープする必要がありますか?

2)各変数をその値で置き換えるためにcat&sedを使用する:

与えられたtemplate.txt:

The number is ${i}
The word is ${word}

コマンド:

cat template.txt | sed -e "s/\${i}/1/" | sed -e "s/\${word}/dog/"

多くの異なるシンボルをエスケープする必要があり、多くの変数があると行が長くなりすぎるので、私には悪いようです。

他のエレガントで安全なソリューションを思いつくことができますか?


回答:


61

あなたはこれを使うことができます:

perl -p -i -e 's/\$\{([^}]+)\}/defined $ENV{$1} ? $ENV{$1} : $&/eg' < template.txt

すべての${...}文字列を対応する環境変数に置き換えます(このスクリプトを実行する前にそれらをエクスポートすることを忘れないでください)。

純粋なbashの場合、これは機能するはずです(変数に$ {...}文字列が含まれていない場合):

#!/bin/bash
while read -r line ; do
    while [[ "$line" =~ (\$\{[a-zA-Z_][a-zA-Z_0-9]*\}) ]] ; do
        LHS=${BASH_REMATCH[1]}
        RHS="$(eval echo "\"$LHS\"")"
        line=${line//$LHS/$RHS}
    done
    echo "$line"
done

。RHSがそれ自体を参照するいくつかの変数を参照してもハングしないソリューション:

#!/bin/bash
line="$(cat; echo -n a)"
end_offset=${#line}
while [[ "${line:0:$end_offset}" =~ (.*)(\$\{([a-zA-Z_][a-zA-Z_0-9]*)\})(.*) ]] ; do
    PRE="${BASH_REMATCH[1]}"
    POST="${BASH_REMATCH[4]}${line:$end_offset:${#line}}"
    VARNAME="${BASH_REMATCH[3]}"
    eval 'VARVAL="$'$VARNAME'"'
    line="$PRE$VARVAL$POST"
    end_offset=${#PRE}
done
echo -n "${line:0:-1}"

警告:bullでNULを使用して入力を正しく処理する方法、または末尾の改行の量を保持する方法がわかりません。シェルがバイナリ入力を「愛する」ため、最後のバリアントはそのまま表示されます。

  1. read バックスラッシュを解釈します。
  2. read -r バックスラッシュを解釈しませんが、最後の行が改行で終わらない場合は最後の行を削除します。
  3. "$(…)"存在するのと同じだけ多くの末尾の改行を削除するので、私は最後; echo -n a使用しますecho -n "${line:0:-1}"。これにより、最後の文字(つまりa)が削除され、入力(行を含む)と同じ数の末尾の改行が保持されます。

3
シェルが厳密な置換を超えないように(たとえば、処理しようとした場合)、bashバージョンに変更[^}]します。[A-Za-Z_][A-Za-z0-9_]${some_unused_var-$(rm -rf $HOME)}
Chris Johnsen、

2
@FractalizeR $&は、perlソリューションで変更したい場合があります""。最初に${...}、置換に失敗した場合はそのままにし、2番目は空の文字列に置き換えます。
ZyX 2010年

5
注:正規表現を一重引用符で囲むbash 3.1から3.2(およびそれ以降)への変更があったようです-正規表現の内容を文字列リテラルとして扱います。...(\ $ \ {[-ZA-Z _] [-ZA-Z_0-9] * \})でなければならない上記の正規表現ので stackoverflow.com/questions/304864/...
ブルーウォーターズ

2
whileループが改行で終了していなくても最後の行を読み取るようにするには、を使用しますwhile read -r line || [[ -n $line ]]; do。さらに、readコマンドは各行から先頭と末尾の空白を取り除きます。これを回避するには、次を使用しますwhile IFS= read -r line || [[ -n $line ]]; do
mklement0 2015年

2
包括的なソリューションを探している人のための制約に注意してください。これらのその他の便利なソリューションでは、変数参照を展開から選択的に保護することはできません(\ エスケープなど)。
mklement0 2015年

138

試す envsubst

FOO=foo
BAR=bar
export FOO BAR

envsubst <<EOF
FOO is $FOO
BAR is $BAR
EOF

11
参考のためにenvsubst、bashはheredocをリテラル二重引用符付き文字列として扱い、その中の変数をすでに補間しているため、heredocを使用する場合は必要ありません。ただし、テンプレートを別のファイルから読み取る場合に最適です。より面倒なものの良い代替品m4
ベポーター、2013

2
このコマンドについて知って、私は非常に嬉しくて驚きました。envsubstの機能を手動で丸めようとしたが、成功しなかった。ありがとうyottatsa!
Tim Stewart、

4
注:envsubstはGNU gettextユーティリティであり、実際にはそれほど堅牢ではありません(gettextは人間のメッセージをローカライズするためのものであるため)。最も重要なのは、バックスラッシュでエスケープされた$ {VAR}置換を認識しないことです(したがって、シェルスクリプトやNginx confファイルのように、実行時に$ VAR置換を使用するテンプレートを持つことはできません)。バックスラッシュエスケープを処理するソリューションについては、私の回答を参照しください。
スチュアートP.ベントレー

4
あなたには、いくつかの理由でenvsubstにこのテンプレートを渡したい場合は、この場合@beporterは、あなたが使用したいと思います<<"EOF"どの、ない補間変数を(引用されたターミネータがヒアドキュメントの単一引用符のようなものです)。
スチュアートP.ベントレー

2
私は次のように使用しました: cat template.txt | envsubst
TruthAdjuster

47

envsubstは私にとって新しいものでした。素晴らしい。

参考までに、ヒアドキュメントを使用することは、confファイルをテンプレート化する優れた方法です。

STATUS_URI="/hows-it-goin";  MONITOR_IP="10.10.2.15";

cat >/etc/apache2/conf.d/mod_status.conf <<EOF
<Location ${STATUS_URI}>
    SetHandler server-status
    Order deny,allow
    Deny from all
    Allow from ${MONITOR_IP}
</Location>
EOF

1
私はこれを私のDockerfile envsubstの追加から節約したcoz よりも優れapt-get install gettext-baseています
TruthAdjuster

テンプレートのようなスクリプトとしてのシェルですが、外部ライブラリがインストールされておらず、トリッキーな表現に対処することによるストレスもありません。
千木郷

35

私はsedの使用に同意します。これは、検索/置換に最適なツールです。これが私のアプローチです:

$ cat template.txt
the number is ${i}
the dog's name is ${name}

$ cat replace.sed
s/${i}/5/
s/${name}/Fido/

$ sed -f replace.sed template.txt > out.txt

$ cat out.txt
the number is 5
the dog's name is Fido

1
これには、置換文字列用の一時ファイルが必要ですよね?一時ファイルなしでそれを行う方法はありますか?
Vladislav Rastrusny、2010年

@FractalizeR:いくつかのバージョンのsedのは、持っている-iに似ているオプション(代わりに編集ファイル)perlのオプションを選択します。sedのマンページを確認してください。
Chris Johnsen、

@FractalizeRはい、sed -iはインラインで置き換えられます。あなたはTclの(他のスクリプト言語)に慣れている場合は、このスレッドをチェックアウト:stackoverflow.com/questions/2818130/...
ハイヴ

次のsedコマンドを使用して、propertyfilesからreplace.sedを作成しました。sed-e 's / ^ / s \ / $ {/ g' -e 's / = /} \ // g' -e 's / $ / \ // g 'the.properties> replace.sed
Jaap D

@hai vuのコードはsedプログラムを作成し、sedの-fフラグを使用してそのプログラムを渡します。必要に応じて、代わりに-eフラグを使用して、sedプログラムの各行をsedに渡すことができます。FWIWテンプレート作成にsedを使用するアイデアが好きです。
Andrew Allbright

23

evalは本当にうまくいくと思います。改行、空白、およびあらゆる種類のbash要素を含むテンプレートを処理します。もちろん、テンプレート自体を完全に制御できる場合:

$ cat template.txt
variable1 = ${variable1}
variable2 = $variable2
my-ip = \"$(curl -s ifconfig.me)\"

$ echo $variable1
AAA
$ echo $variable2
BBB
$ eval "echo \"$(<template.txt)\"" 2> /dev/null
variable1 = AAA
variable2 = BBB
my-ip = "11.22.33.44"

もちろん、evalは任意のコードを実行できるため、このメソッドは注意して使用する必要があります。これをrootとして実行することはほとんど問題外です。テンプレート内の引用符はエスケープする必要がありますeval。そうしないと、によって使用されます。

ご希望の場合にも、ヒアドキュメントを使用することができますcatecho

$ eval "cat <<< \"$(<template.txt)\"" 2> /dev/null

@plockcは、bashの引用エスケープの問題を回避するソリューションを提供しました。

$ eval "cat <<EOF
$(<template.txt)
EOF
" 2> /dev/null

編集:これをsudoを使用してrootとして実行することに関する部分を削除しました...

編集:引用符をエスケープする方法についてのコメントを追加し、plockcのソリューションをミックスに追加しました!


これにより、テンプレート内の引用が取り除かれ、単一引用符内で置き換えられないため、テンプレートの形式によっては、微妙なバグが発生する可能性があります。ただし、これはおそらくすべてのBashベースのテンプレートメソッドに適用できます。
Alex B

IMHO Bashベースのテンプレートは狂っています。テンプレートの機能を理解するにはbashプログラマーである必要があるからです。しかしコメントをありがとう!
mogsie 2014年

@AlexB:このアプローチ、単一引用符の間で置き換えられます。これらは、evaled echo / catコマンドが処理するときに、文字列区切り文字ではなく、二重引用符で囲まれた文字列内の単なるリテラル文字だからです。試してくださいeval "echo \"'\$HOME'\""
mklement0 2015年

21

私はmogsieのようなbashソリューションを持っていますが、二重引用符をエスケープしないようにするために、herestringの代わりにheredocを使用しています

eval "cat <<EOF
$(<template.txt)
EOF
" 2> /dev/null

4
このソリューションは、テンプレートでのBashパラメータの拡張をサポートしています。私のお気に入りは、必須パラメーター${param:?}、オプションのパラメーターの周囲にテキストをネストしています。例:${DELAY:+<delay>$DELAY</delay>}DELAYが未定義の場合は何も展開せず、DELAY = 17の場合は<delay> 17 </ delay>に展開されます。
Eric Bolinger、2015

2
ああ!また、EOF区切り文字はPIDなどの動的文字列を使用できます_EOF_$$
Eric Bolinger、2015

1
@ mklement0末尾の改行の回避策は、空の変数などの展開を使用するか$trailing_newline、または使用$NL5して、5つの改行として展開されることを確認します。
xebeche

@xebeche:はい、あなたは非常にエンドで示唆置く内部のtemplate.txt末尾の改行を維持するために働くだろう。
mklement0 2016

1
洗練されたソリューションですが、コマンド置換により、入力ファイルから末尾の改行が削除されることに注意してください。ただし、これは通常問題にはなりません。別のエッジケース:の使用に起因するeval場合は、template.txt含まれているEOF独自の行に、それは時期尚早ここ-docの終了、したがって、コマンドを破りますよ。(@xebecheへの帽子のヒント)。
mklement0 16

18

2017年1月6日を編集

構成ファイルで二重引用符を保持する必要があったので、sedで二重引用符を二重にエスケープすると、次のことが可能になります。

render_template() {
  eval "echo \"$(sed 's/\"/\\\\"/g' $1)\""
}

後続の新しい行を保持することは考えられませんが、間に空行が保持されます。


古いトピックですが、IMOはここでよりエレガントなソリューションを見つけました:http : //pempek.net/articles/2013/07/08/bash-sh-as-template-engine/

#!/bin/sh

# render a template configuration file
# expand variables + preserve formatting
render_template() {
  eval "echo \"$(cat $1)\""
}

user="Gregory"
render_template /path/to/template.txt > path/to/configuration_file

GrégoryPakoszへのすべてのクレジット。


これにより、入力から二重引用符が削除され、入力ファイルに複数の末尾の改行がある場合、それらは単一の行に置き換えられます。
mklement0 2015年

2
私は、すなわち、それを動作させるために2つの少ないバックスラッシュを必要 eval "echo \"$(sed 's/\"/\\"/g' $1)\""
デビッドバウ

残念ながら、このアプローチでは、phpファイル(にはが含まれています$variables)のテンプレートを作成できません。
IStranger

10

ホイールを再発明する代わりに、envsubstを 使用してください。たとえばDockerコンテナーの環境変数から構成ファイルを構築するなど、ほとんどすべてのシナリオで使用できます。

Macの場合、自作があることを確認してからgettextからリンクします。

brew install gettext
brew link --force gettext

./template.cfg

# We put env variables into placeholders here
this_variable_1 = ${SOME_VARIABLE_1}
this_variable_2 = ${SOME_VARIABLE_2}

./.env:

SOME_VARIABLE_1=value_1
SOME_VARIABLE_2=value_2

./configure.sh

#!/bin/bash
cat template.cfg | envsubst > whatever.cfg

今すぐそれを使用してください:

# make script executable
chmod +x ./configure.sh
# source your variables
. .env
# export your variables
# In practice you may not have to manually export variables 
# if your solution depends on tools that utilise .env file 
# automatically like pipenv etc. 
export SOME_VARIABLE_1 SOME_VARIABLE_2
# Create your config file
./configure.sh

この呼び出しシーケンスはenvsubst実際に機能します。
Alex

envsubstMacOSで動作しない他の人にとっては、homebrew:を使用してインストールする必要がありますbrew install gettext
マット

9

受け入れられた回答のより長くより堅牢なバージョン:

perl -pe 's;(\\*)(\$([a-zA-Z_][a-zA-Z_0-9]*)|\$\{([a-zA-Z_][a-zA-Z_0-9]*)\})?;substr($1,0,int(length($1)/2)).($2&&length($1)%2?$2:$ENV{$3||$4});eg' template.txt

これにより$VAR すべてのインスタンスが${VAR}その環境値(または、未定義の場合は空の文字列)に展開されます。

バックスラッシュを適切にエスケープし、バックスラッシュでエスケープされた$を受け入れて置換を禁止します(envsubstとは異なり、envsubstはこれを行いません)。

したがって、環境が次の場合:

FOO=bar
BAZ=kenny
TARGET=backslashes
NOPE=engi

そしてあなたのテンプレートは:

Two ${TARGET} walk into a \\$FOO. \\\\
\\\$FOO says, "Delete C:\\Windows\\System32, it's a virus."
$BAZ replies, "\${NOPE}s."

結果は次のようになります。

Two backslashes walk into a \bar. \\
\$FOO says, "Delete C:\Windows\System32, it's a virus."
kenny replies, "${NOPE}s."

$の前のバックスラッシュのみをエスケープしたい場合(テンプレートに「C:\ Windows \ System32」を変更せずに書き込むことができます)、次のわずかに変更されたバージョンを使用します。

perl -pe 's;(\\*)(\$([a-zA-Z_][a-zA-Z_0-9]*)|\$\{([a-zA-Z_][a-zA-Z_0-9]*)\});substr($1,0,int(length($1)/2)).(length($1)%2?$2:$ENV{$3||$4});eg' template.txt

8

私はこの方法でこれを行ったでしょう。おそらく効率は落ちますが、読みやすく、保守しやすくなります。

TEMPLATE='/path/to/template.file'
OUTPUT='/path/to/output.file'

while read LINE; do
  echo $LINE |
  sed 's/VARONE/NEWVALA/g' |
  sed 's/VARTWO/NEWVALB/g' |
  sed 's/VARTHR/NEWVALC/g' >> $OUTPUT
done < $TEMPLATE

10
あなたは、唯一のSEDの呼び出しでライン・バイ・ラインを読まずにこれを行うことができます:sed -e 's/VARONE/NEWVALA/g' -e 's/VARTWO/NEWVALB/g' -e 's/VARTHR/NEWVALC/g' < $TEMPLATE > $OUTPUT
ブランドンブルーム

8

あなたが使用したい場合はJinja2のの:テンプレートを、このプロジェクトを参照j2cliを

それはサポートします:

  • JSON、INI、YAMLファイルおよび入力ストリームからのテンプレート
  • 環境変数からのテンプレート

5

純粋なbashを使用してZyXから答えを受け取りますが、新しいスタイルの正規表現マッチングと間接的なパラメータ置換を使用すると、次のようになります。

#!/bin/bash
regex='\$\{([a-zA-Z_][a-zA-Z_0-9]*)\}'
while read line; do
    while [[ "$line" =~ $regex ]]; do
        param="${BASH_REMATCH[1]}"
        line=${line//${BASH_REMATCH[0]}/${!param}}
    done
    echo $line
done

5

Perlの使用がオプションであり、(すべてのシェル変数ではなく環境変数のみに基づく拡張に満足している場合は、Stuart P. Bentleyの堅牢な答えを検討してくださいください。

この答えは、使用しても安全に使用できるbashのみのソリューションを提供することを目的としていますeval

目標は以下のとおりです。

  • ${name}および$name変数参照の両方の拡張をサポートします。
  • 他のすべての拡張を防止します。
    • コマンド置換($(...)およびレガシー構文`...`
    • 算術置換($((...))および従来の構文$[...])。
  • \\${name})を前に付けることで、変数展開を選択的に抑制できます。
  • 特殊文字を保持します。特に入力"\インスタンスで。
  • 引数またはstdinを介した入力を許可します。

機能expandVars()

expandVars() {
  local txtToEval=$* txtToEvalEscaped
  # If no arguments were passed, process stdin input.
  (( $# == 0 )) && IFS= read -r -d '' txtToEval
  # Disable command substitutions and arithmetic expansions to prevent execution
  # of arbitrary commands.
  # Note that selectively allowing $((...)) or $[...] to enable arithmetic
  # expressions is NOT safe, because command substitutions could be embedded in them.
  # If you fully trust or control the input, you can remove the `tr` calls below
  IFS= read -r -d '' txtToEvalEscaped < <(printf %s "$txtToEval" | tr '`([' '\1\2\3')
  # Pass the string to `eval`, escaping embedded double quotes first.
  # `printf %s` ensures that the string is printed without interpretation
  # (after processing by by bash).
  # The `tr` command reconverts the previously escaped chars. back to their
  # literal original.
  eval printf %s "\"${txtToEvalEscaped//\"/\\\"}\"" | tr '\1\2\3' '`(['
}

例:

$ expandVars '\$HOME="$HOME"; `date` and $(ls)'
$HOME="/home/jdoe"; `date` and $(ls)  # only $HOME was expanded

$ printf '\$SHELL=${SHELL}, but "$(( 1 \ 2 ))" will not expand' | expandVars
$SHELL=/bin/bash, but "$(( 1 \ 2 ))" will not expand # only ${SHELL} was expanded
  • パフォーマンス上の理由から、関数はstdin入力を一度にメモリに読み込みますが、関数を行ごとのアプローチに適合させるのは簡単です。
  • 埋め込みコマンドや算術置換が含まれていない限り、などの非基本変数展開もサポートします。${HOME:0:10}${HOME:0:$(echo 10)}
    • このような埋め込まれた置換は実際には関数を中断します(すべて$(`インスタンスが盲目的にエスケープされるため)。
    • 同様に、不正な変数参照${HOME((})BREAK関数の。
  • bashは二重引用符で囲まれた文字列を処理するため、バックスラッシュは次のように処理されます。
    • \$name 拡張を防ぎます。
    • \続かないシングル$はそのまま保存されます。
    • 複数の隣接 \インスタンスを表す場合は、それらを2倍にする必要があります。例えば:
      • \\-> \-と同じ\
      • \\\\ -> \\
    • 入力は、内部目的のために使用されている以下の(ほとんど使用されません)文字を含めることはできません:0x10x20x3
  • bashが新しい拡張構文を導入する必要がある場合、この関数がそのような拡張を妨げない可能性があるという主に仮定的な懸念があります-を使用しないソリューションについては、以下を参照してくださいeval

展開のみをサポートするより制限的なソリューションを${name}探している場合-つまり、参照を無視して必須の中括弧を使用する場合$name- 私のこの回答を参照してください。


ここでは受け入れられた回答からのbashのみの、eval-freeソリューションの改良版を示します

改善点は次のとおりです。

  • ${name}および$name変数参照の両方の拡張のサポート。
  • \拡張すべきではない変数参照のエスケープのサポート。
  • eval上記のベースのソリューションとは異なり、
    • 非基本的な展開は無視されます
    • 不正な変数の参照は無視されます(スクリプトを壊しません)
 IFS= read -d '' -r lines # read all input from stdin at once
 end_offset=${#lines}
 while [[ "${lines:0:end_offset}" =~ (.*)\$(\{([a-zA-Z_][a-zA-Z_0-9]*)\}|([a-zA-Z_][a-zA-Z_0-9]*))(.*) ]] ; do
      pre=${BASH_REMATCH[1]} # everything before the var. reference
      post=${BASH_REMATCH[5]}${lines:end_offset} # everything after
      # extract the var. name; it's in the 3rd capture group, if the name is enclosed in {...}, and the 4th otherwise
      [[ -n ${BASH_REMATCH[3]} ]] && varName=${BASH_REMATCH[3]} || varName=${BASH_REMATCH[4]}
      # Is the var ref. escaped, i.e., prefixed with an odd number of backslashes?
      if [[ $pre =~ \\+$ ]] && (( ${#BASH_REMATCH} % 2 )); then
           : # no change to $lines, leave escaped var. ref. untouched
      else # replace the variable reference with the variable's value using indirect expansion
           lines=${pre}${!varName}${post}
      fi
      end_offset=${#pre}
 done
 printf %s "$lines"

5

次に、別の純粋なbashソリューションを示します。

  • ヒアドキュメントを使用しているので、
    • 構文が追加で必要になるため、複雑さは増しません
    • テンプレートにはbashコードを含めることができます
      • また、適切にインデントすることもできます。下記参照。
  • evalを使用しないため、次のようになります。
    • 末尾の空行のレンダリングに問題はありません
    • テンプレートの引用に問題はありません

$ cat code

#!/bin/bash
LISTING=$( ls )

cat_template() {
  echo "cat << EOT"
  cat "$1"
  echo EOT
}

cat_template template | LISTING="$LISTING" bash

$ cat template (末尾の改行と二重引用符付き)

<html>
  <head>
  </head>
  <body> 
    <p>"directory listing"
      <pre>
$( echo "$LISTING" | sed 's/^/        /' )
      <pre>
    </p>
  </body>
</html>

出力

<html>
  <head>
  </head>
  <body> 
    <p>"directory listing"
      <pre>
        code
        template
      <pre>
    </p>
  </body>
</html>

4

これが別の解決策です。すべての変数とテンプレートファイルの内容を含むbashスクリプトを生成します。そのスクリプトは次のようになります。

word=dog           
i=1                
cat << EOF         
the number is ${i} 
the word is ${word}

EOF                

このスクリプトをbashにフィードすると、目的の出力が生成されます。

the number is 1
the word is dog

そのスクリプトを生成してbashにフィードする方法は次のとおりです。

(
    # Variables
    echo word=dog
    echo i=1

    # add the template
    echo "cat << EOF"
    cat template.txt
    echo EOF
) | bash

討論

  • 括弧はサブシェルを開き、その目的は生成されたすべての出力をグループ化することです
  • サブシェル内で、すべての変数宣言を生成します
  • また、サブシェルでは、 catサブシェルで、HEREDOCコマンドします
  • 最後に、サブシェルの出力をbashに送り、必要な出力を生成します
  • この出力をファイルにリダイレクトする場合は、最後の行を次のように置き換えます。

    ) | bash > output.txt

3

このページはawkで回答を説明しています

awk '{while(match($0,"[$]{[^}]*}")) {var=substr($0,RSTART+2,RLENGTH -3);gsub("[$]{"var"}",ENVIRON[var])}}1' < input.txt > output.txt

これにより、すべての見積もりが損なわれません。すごい!
Pepster

3

shtplに最適なケース。(私のプロジェクトなので、広く使用されておらず、ドキュメントが不足しています。しかし、とにかくこれが提供するソリューションです。テストしてみてください。)

ただ実行する:

$ i=1 word=dog sh -c "$( shtpl template.txt )"

結果は次のとおりです。

the number is 1
the word is dog

楽しんで。


1
それががらくたであるなら、とにかくそれは反対投票です。そして、私はそれで大丈夫です。しかし、わかりました、はっきりとは見えませんが、実際には私のプロジェクトです。将来的にもっと目に見えるようにするつもりです。とにかくコメントと時間をいただきありがとうございます。
zstegi 2013

追加したいのは、昨日本当にユースケースを検索したことです。shtplは完璧なソリューションです。うん、退屈だった...
zstegi

3
# Usage: template your_file.conf.template > your_file.conf
template() {
        local IFS line
        while IFS=$'\n\r' read -r line ; do
                line=${line//\\/\\\\}         # escape backslashes
                line=${line//\"/\\\"}         # escape "
                line=${line//\`/\\\`}         # escape `
                line=${line//\$/\\\$}         # escape $
                line=${line//\\\${/\${}       # de-escape ${         - allows variable substitution: ${var} ${var:-default_value} etc
                # to allow arithmetic expansion or command substitution uncomment one of following lines:
#               line=${line//\\\$\(/\$\(}     # de-escape $( and $(( - allows $(( 1 + 2 )) or $( command ) - UNSECURE
#               line=${line//\\\$\(\(/\$\(\(} # de-escape $((        - allows $(( 1 + 2 ))
                eval "echo \"${line}\"";
        done < "$1"
}

これは、好みに合わせて調整可能な純粋なbash関数であり、本番環境で使用され、入力を中断しないでください。壊れた場合はお知らせください。



0

空白を保持するbash関数は次のとおりです。

# Render a file in bash, i.e. expand environment variables. Preserves whitespace.
function render_file () {
    while IFS='' read line; do
        eval echo \""${line}"\"
    done < "${1}"
}

0

perl他のいくつかの回答に基づいて変更されたスクリプトは次のとおりです。

perl -pe 's/([^\\]|^)\$\{([a-zA-Z_][a-zA-Z_0-9]*)\}/$1.$ENV{$2}/eg' -i template

機能(私のニーズに基づいていますが、簡単に変更できるはずです):

  • エスケープされたパラメータ展開をスキップします(例:\ $ {VAR})。
  • $ {VAR}形式のパラメーター展開をサポートしますが、$ VARはサポートしません。
  • VAR envarがない場合は、$ {VAR}を空の文字列に置き換えます。
  • 名前でaz、AZ、0-9、および下線文字のみをサポートします(最初の桁の数字を除く)。

0

ここで単純な変数置換のpythonスクリプトを見てください:https : //github.com/jeckep/vsubst

使い方はとても簡単です。

python subst.py --props secure.properties --src_path ./templates --dst_path ./dist

0

この素晴らしい質問に対する私の謙虚な貢献。

tpl() {
    local file=$(cat - | \
                 sed -e 's/\"/\\"/g' \
                     -e "s/'/\\'/g")
    local vars=$(echo ${@} | tr ' ' ';')
    echo "$(sh -c "${vars};echo \"$file\"")"
}

cat tpl.txt | tpl "one=fish" "two=fish"

これは基本的に、サブシェルを使用してenvar置換を行うことで機能しますが、evalを使用せず、一重引用符と二重引用符を明示的にエスケープします。var式をスペースなしの1行に連結して混乱させないようにしsh、次にテンプレートをechoに渡してsh、varの置換を処理します。改行、コメントなどを保存します。varを\${like_this}解釈したくない場合はエスケープできます。${missing_var}空の値に置き換えられるだけです。

ここでの他の答えの多くは非常に良いですが、私は非常にシンプルなものが欲しかったので、現在持っているテンプレートケースのすべての可能なケースを文字通り処理する必要はありません。

楽しい!


0

このページのplockcの回答をフォローアップするために、バシズムを避けたいと思っている人のために、ダッシュに適したバージョンを示します。

eval "cat <<EOF >outputfile
$( cat template.in )
EOF
" 2> /dev/null

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