テキストファイル内の$ {}プレースホルダーを置き換える方法
-
03-07-2019 - |
質問
" template"の出力をパイプしたい $ {dbName}
のような変数が散在するファイルにMySQLに保存します。これらのインスタンスを置き換え、出力を標準出力にダンプするコマンドラインユーティリティとは何ですか?
解決
Sed !
指定されたtemplate.txt:
The number is ${i} The word is ${word}
言う必要があります:
sed -e "s/\${i}/1/" -e "s/\${word}/dog/" template.txt
複数の -e
引数を同じ sed
呼び出しに渡すヒントをくれたJonathan Lefflerに感謝します。
他のヒント
更新
これは、$ VARや$ {VARなどの変数の置換のみを行う同様の質問に関する yottatsa のソリューションです。 }、簡単なワンライナーです
i=32 word=foo envsubst < template.txt
もちろん、あなたの環境に i と word があれば、それはただ
envsubst < template.txt
Macでは、 gettext の一部として、および MacGPG2
からインストールされたように見えます古い回答
同様の質問に対する mogsie からのソリューションの改善点です。私のソリューションでは、二重にスケールする必要はありません。 mogsieは引用していますが、彼は1つのライナーです!
eval "cat <<EOF
$(<template.txt)
EOF
" 2> /dev/null
これらの2つのソリューションの利点は、通常は発生しない少数のタイプのシェル拡張のみを取得することです。ただし、$((...))、 `...`、および$(...)ここではバックスラッシュは エスケープ文字ですが、解析にバグがあることを心配する必要はなく、複数行で問題ありません。
/ bin / sh
を使用します。変数を設定する小さなシェルスクリプトを作成し、シェル自体を使用してテンプレートを解析します。そのようにします(改行を正しく処理するために編集します):
file 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"
出力:
#sh script.sh
the number is 1
the word is dog
最近の関心を考えて、これについてもう一度考えていましたが、当初考えていたツールは m4
、autotoolsのマクロプロセッサ。したがって、最初に指定した変数の代わりに、次を使用します。
$echo 'I am a DBNAME' | m4 -DDBNAME="database name"
template.txt
Variable 1 value: ${var1}
Variable 2 value: ${var2}
data.sh
#!/usr/bin/env bash
declare var1="value 1"
declare var2="value 2"
parser.sh
#!/usr/bin/env bash
# args
declare file_data=$1
declare file_input=$2
declare file_output=$3
source $file_data
eval "echo \"$(< $file_input)\"" > $file_output
./ parser.sh data.sh template.txt parsed_file.txt
parsed_file.txt
Variable 1 value: value 1
Variable 2 value: value 2
環境変数を置き換える、以前の回答に基づいたperlでの私のソリューションです:
perl -p -e 's/\$\{(\w+)\}/(exists $ENV{$1}?$ENV{$1}:"missing variable $1")/eg' < infile > outfile
eval
を使用しても安全に使用できる堅牢なBash関数があります。
入力テキスト内のすべての $ {varName}
変数参照は、呼び出しシェルの変数に基づいて展開されます。
他に何も展開されません:名前が not で {...}
で囲まれた変数参照( $など) varName
)、コマンド置換( $(...)
およびレガシー構文 `...`
)、算術置換( $( (...))
および従来の構文 $ [...]
)。
$
をリテラルとして扱うには、 \
-escape;例: \ $ {HOME}
入力は stdin を介してのみ受け付けられることに注意してください。
例:
$ expandVarsStrict <<<'$HOME is "${HOME}"; `date` and \$(ls)' # only ${HOME} is expanded
$HOME is "/Users/jdoe"; `date` and $(ls)
関数のソースコード:
expandVarsStrict(){
local line lineEscaped
while IFS= read -r line || [[ -n $line ]]; do # the `||` clause ensures that the last line is read even if it doesn't end with \n
# Escape ALL chars. that could trigger an expansion..
IFS= read -r -d '' lineEscaped < <(printf %s "$line" | tr '`([
この関数は、 0x1
、 0x2
、 0x3
、および 0x4
の制御文字がないことを前提としていますこれらの文字のため、入力に存在します。内部的に使用されます-この関数は text を処理するため、これは安全な前提となるはずです。
'\1\2\3\4')
# ... then selectively reenable ${ references
lineEscaped=${lineEscaped//
この関数は、 0x1
、 0x2
、 0x3
、および 0x4
の制御文字がないことを前提としていますこれらの文字のため、入力に存在します。内部的に使用されます-この関数は text を処理するため、これは安全な前提となるはずです。
\4'{/\${}
# Finally, escape embedded double quotes to preserve them.
lineEscaped=${lineEscaped//\"/\\\"}
eval "printf '%s\n' \"$lineEscaped\"" | tr '\1\2\3\4' '`([
この関数は、 0x1
、 0x2
、 0x3
、および 0x4
の制御文字がないことを前提としていますこれらの文字のため、入力に存在します。内部的に使用されます-この関数は text を処理するため、これは安全な前提となるはずです。
done
}
この関数は、 0x1
、 0x2
、 0x3
、および 0x4
の制御文字がないことを前提としていますこれらの文字のため、入力に存在します。内部的に使用されます-この関数は text を処理するため、これは安全な前提となるはずです。
Perl の使用を受け入れている場合、それが私の提案です。おそらく sed や AWK のエキスパートは、おそらくこれをはるかに簡単にする方法を知っているでしょう。置換用のdbNameだけでなく、より複雑なマッピングがある場合、これを非常に簡単に拡張できますが、その時点で標準のPerlスクリプトに配置することもできます。
perl -p -e 's/\$\{dbName\}/testdb/s' yourfile | mysql
もう少し複雑なことを行う(複数のキーを処理する)短いPerlスクリプト:
#!/usr/bin/env perl
my %replace = ( 'dbName' => 'testdb', 'somethingElse' => 'fooBar' );
undef $/;
my $buf = <STDIN>;
$buf =~ s/\$\{ Perl の使用を受け入れている場合、それが私の提案です。おそらく sed や AWK のエキスパートは、おそらくこれをはるかに簡単にする方法を知っているでしょう。置換用のdbNameだけでなく、より複雑なマッピングがある場合、これを非常に簡単に拡張できますが、その時点で標準のPerlスクリプトに配置することもできます。
perl -p -e 's/\$\{dbName\}/testdb/s' yourfile | mysql
もう少し複雑なことを行う(複数のキーを処理する)短いPerlスクリプト:
replace-script < yourfile | mysql
上記のスクリプトにreplace-scriptという名前を付けると、次のように使用できます。
<*>\}/$replace{ Perl の使用を受け入れている場合、それが私の提案です。おそらく sed や AWK のエキスパートは、おそらくこれをはるかに簡単にする方法を知っているでしょう。置換用のdbNameだけでなく、より複雑なマッピングがある場合、これを非常に簡単に拡張できますが、その時点で標準のPerlスクリプトに配置することもできます。
perl -p -e 's/\$\{dbName\}/testdb/s' yourfile | mysql
もう少し複雑なことを行う(複数のキーを処理する)短いPerlスクリプト:
<*>
上記のスクリプトにreplace-scriptという名前を付けると、次のように使用できます。
<*>}/g for keys %replace;
print $buf;
上記のスクリプトにreplace-scriptという名前を付けると、次のように使用できます。
<*> rendertemplate.sh
の作成:
#!/usr/bin/env bash
eval "echo \"$(cat $1)\""
そして template.tmpl
:
Hello, ${WORLD}
Goodbye, ${CHEESE}
テンプレートのレンダリング:
$ export WORLD=Foo
$ CHEESE=Bar ./rendertemplate.sh template.tmpl
Hello, Foo
Goodbye, Bar
file.tpl:
The following bash function should only replace ${var1} syntax and ignore
other shell special chars such as `backticks` or $var2 or "double quotes".
If I have missed anything - let me know.
script.sh:
template(){
# usage: template file.tpl
while read -r line ; do
line=${line//\"/\\\"}
line=${line//\`/\\\`}
line=${line//\$/\\\$}
line=${line//\\\${/\${}
eval "echo \"$line\"";
done < ${1}
}
var1="*replaced*"
var2="*not replaced*"
template file.tpl > result.txt
Sigil のようなものを使用することをお勧めします。 https://github.com/gliderlabs/sigil
単一のバイナリにコンパイルされるため、システムへのインストールは非常に簡単です。
その後、次のような簡単なワンライナーを実行できます。
cat my-file.conf.template | sigil -p $(env) > my-file.conf
これは eval
よりもはるかに安全で、regexまたは sed
同じことを考えながら、このスレッドを見つけました。私はこれにインスピレーションを得ました(バッククティックに注意してください)
$ echo $MYTEST
pass!
$ cat FILE
hello $MYTEST world
$ eval echo `cat FILE`
hello pass! world
ここには多くの選択肢がありますが、私はヒープ上で私のものを投げると思いました。 perlベースで、$ {...}の形式の変数のみを対象とし、ファイルを引数として処理し、変換されたファイルをstdoutに出力します。
use Env;
Env::import();
while(<>) { ここには多くの選択肢がありますが、私はヒープ上で私のものを投げると思いました。 perlベースで、$ {...}の形式の変数のみを対象とし、ファイルを引数として処理し、変換されたファイルをstdoutに出力します。
<*>
もちろん、私は実際にはperlの人間ではないので、致命的な欠陥が簡単に発生する可能性があります(私にとってはうまくいきます)。
=~ s/(\${\w+})/$1/eeg; $text .= ここには多くの選択肢がありますが、私はヒープ上で私のものを投げると思いました。 perlベースで、$ {...}の形式の変数のみを対象とし、ファイルを引数として処理し、変換されたファイルをstdoutに出力します。
<*>
もちろん、私は実際にはperlの人間ではないので、致命的な欠陥が簡単に発生する可能性があります(私にとってはうまくいきます)。
; }
print "$text";
もちろん、私は実際にはperlの人間ではないので、致命的な欠陥が簡単に発生する可能性があります(私にとってはうまくいきます)。
構成ファイル形式を制御できる場合、bash自体で実行できます。構成ファイルをサブシェル化するのではなく、ソース(&quot;。&quot;)するだけです。これにより、変数はサブシェル(サブシェルが終了すると変数が消える)ではなく、現在のシェルのコンテキストで作成され(存在し続ける)ことが保証されます。
$ cat config.data
export parm_jdbc=jdbc:db2://box7.co.uk:5000/INSTA
export parm_user=pax
export parm_pwd=never_you_mind
$ cat go.bash
. config.data
echo "JDBC string is " $parm_jdbc
echo "Username is " $parm_user
echo "Password is " $parm_pwd
$ bash go.bash
JDBC string is jdbc:db2://box7.co.uk:5000/INSTA
Username is pax
Password is never_you_mind
設定ファイルをシェルスクリプトにできない場合は、実行する前に「コンパイル」するだけです(コンパイルは入力形式によって異なります)。
$ cat config.data
parm_jdbc=jdbc:db2://box7.co.uk:5000/INSTA # JDBC URL
parm_user=pax # user name
parm_pwd=never_you_mind # password
$ cat go.bash
cat config.data
| sed 's/#.*$//'
| sed 's/[ \t]*$//'
| sed 's/^[ \t]*//'
| grep -v '^
特定のケースでは、次のようなものを使用できます:
$ cat config.data
export p_p1=val1
export p_p2=val2
$ cat go.bash
. ./config.data
echo "select * from dbtable where p1 = '$p_p1' and p2 like '$p_p2%' order by p1"
$ bash go.bash
select * from dbtable where p1 = 'val1' and p2 like 'val2%' order by p1
次にgo.bashの出力をMySQLと出来上がりにパイプします。データベースを破壊しないことを願っています:-)。
| sed 's/^/export '
>config.data-compiled
. config.data-compiled
echo "JDBC string is " $parm_jdbc
echo "Username is " $parm_user
echo "Password is " $parm_pwd
$ bash go.bash
JDBC string is jdbc:db2://box7.co.uk:5000/INSTA
Username is pax
Password is never_you_mind
特定のケースでは、次のようなものを使用できます:
<*>次にgo.bashの出力をMySQLと出来上がりにパイプします。データベースを破壊しないことを願っています:-)。
これは、代わりにファイルの内容が二重引用符の間に入力されたかのように、シェルに置換を行わせる方法です。
内容を含むtemplate.txtの例を使用する:
The number is ${i}
The word is ${word}
次の行により、シェルはtemplate.txtの内容を補間し、結果を標準出力に書き込みます。
i='1' word='dog' sh -c 'echo "'"$(cat template.txt)"'"'
説明:
-
i
およびword
は、sh
の実行にスコーピングされた環境変数として渡されます。 -
sh
は、渡された文字列の内容を実行します。 - 互いに隣り合って記述された文字列は1つの文字列になります。
- '
echo&quot;
' +&quot;$(cat template.txt)
&quot; + '&quot;
'
- '
- 置換は
&quot;
と&quot;$(cat template.txt)
&quot;の間にあるため、cat template.txt
の出力になります。 - したがって、
sh -c
によって実行されるコマンドは次のようになります。-
echo&quot;数字は$ {i} \ n単語は$ {word}&quot;
、 -
i
およびword
は、指定された環境変数です。
-