我想将一个“模板”文件的输出管道到MySQL中,该文件具有像${dbName}这样的变量。替换这些实例并将输出转储到标准输出的命令行实用程序是什么?

输入文件被认为是安全的,但是可能存在错误的替换定义。执行替换应避免执行意外的代码执行。


当前回答

我建议使用像Sigil这样的东西: https://github.com/gliderlabs/sigil

它被编译成一个二进制文件,所以在系统上安装它非常容易。

然后你可以像下面这样简单的一行代码:

cat my-file.conf.template | sigil -p $(env) > my-file.conf

这比eval更安全,比使用regex或sed更容易

其他回答

下面是一种让shell为您执行替换的方法,就像在双引号之间输入文件的内容一样。

以包含内容的template.txt为例:

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

下面的代码行将使shell插入template.txt的内容并将结果写入标准输出。

i='1' word='dog' sh -c 'echo "'"$(cat template.txt)"'"'

解释:

I和word作为环境变量传递给sh的执行。 Sh执行传入的字符串的内容。 相邻的字符串变成一个字符串,这个字符串就是: “echo”+“$(cat template.txt)”+ " ' 由于替换在"之间,"$(cat template.txt)"成为cat template.txt的输出。 因此sh -c执行的命令变成: echo“数字是${i}\n字是${word}”, 其中I和word是指定的环境变量。

如果您愿意使用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编辑潜在的多个文件,与备份。

  perl -e 's/\$\{([^}]+)\}/defined $ENV{$1} ? $ENV{$1} : ""/eg' \
    -i.orig \
    -p config/test/*

创建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

更新

下面是yottatsa关于类似问题的解决方案,它只替换像$VAR或${VAR}这样的变量,并且是一个简短的一行程序

i=32 word=foo envsubst < template.txt

当然,如果i和word在你的环境中,那么它只是

envsubst < template.txt

在我的Mac上,它看起来是作为gettext和MacGPG2的一部分安装的

旧的答案

这里是一个改进的解决方案从mogsie对类似的问题,我的解决方案不需要你的双引号,mogsie的做,但他是一个一行!

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

这两种解决方案的强大之处在于,您只能获得几种正常情况下不会发生的shell扩展类型$((…)),'…',和$(…),虽然反斜杠在这里是一个转义字符,但您不必担心解析有bug,它可以很好地处理多行。