我想将一个“模板”文件的输出管道到MySQL中,该文件具有像${dbName}这样的变量。替换这些实例并将输出转储到标准输出的命令行实用程序是什么?
输入文件被认为是安全的,但是可能存在错误的替换定义。执行替换应避免执行意外的代码执行。
我想将一个“模板”文件的输出管道到MySQL中,该文件具有像${dbName}这样的变量。替换这些实例并将输出转储到标准输出的命令行实用程序是什么?
输入文件被认为是安全的,但是可能存在错误的替换定义。执行替换应避免执行意外的代码执行。
当前回答
创建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
其他回答
如果您愿意使用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/\$\{$_\}/$replace{$_}/g for keys %replace;
print $buf;
如果你将上面的脚本命名为replace-script,那么它可以像下面这样使用:
replace-script < yourfile | mysql
这里有很多选择,但我想把我的扔到堆里。它是基于perl的,只针对形式为${…},将要处理的文件作为参数,并在stdout上输出转换后的文件:
use Env;
Env::import();
while(<>) { $_ =~ s/(\${\w+})/$1/eeg; $text .= $_; }
print "$text";
当然,我不是一个真正的perl人,所以很容易有一个致命的缺陷(对我来说是如此)。
我在想同样的事情时发现了这条线索。这启发了我(注意反节拍)
$ echo $MYTEST
pass!
$ cat FILE
hello $MYTEST world
$ eval echo `cat FILE`
hello pass! world
对我来说,这是最简单和最强大的解决方案,你甚至可以使用相同的命令eval echo "$(<template.txt)包含其他模板:
带有嵌套模板的示例
创建模板文件,变量是常规bash语法${VARIABLE_NAME}或$VARIABLE_NAME
你必须在模板中用\转义特殊字符,否则它们将被eval解释。
template.txt
Hello ${name}!
eval echo $(<nested-template.txt)
nested-template.txt
Nice to have you here ${name} :\)
创建源文件
template.source
declare name=royman
解析模板
source template.source && eval echo "$(<template.txt)"
输出
Hello royman!
Nice to have you here royman :)
这里有一个健壮的Bash函数,尽管使用了eval,但使用起来应该是安全的。
输入文本中的所有${varName}变量引用都是基于调用shell的变量展开的。
没有其他内容被展开:没有包含在{…}(例如$varName)、命令替换($(…)和遗留语法'…')、算术替换($((…))和遗留语法$[…])。
要将$作为一个文字,\-转义它;例如:\ ${回家}
注意,输入只通过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 '`([$' '\1\2\3\4')
# ... then selectively reenable ${ references
lineEscaped=${lineEscaped//$'\4'{/\${}
# Finally, escape embedded double quotes to preserve them.
lineEscaped=${lineEscaped//\"/\\\"}
eval "printf '%s\n' \"$lineEscaped\"" | tr '\1\2\3\4' '`([$'
done
}
该函数假设输入中不存在0x1、0x2、0x3和0x4控制字符,因为这些字符。在内部使用—因为函数处理文本,所以这应该是一个安全的假设。