我想将一个“模板”文件的输出管道到MySQL中,该文件具有像${dbName}这样的变量。替换这些实例并将输出转储到标准输出的命令行实用程序是什么?
输入文件被认为是安全的,但是可能存在错误的替换定义。执行替换应避免执行意外的代码执行。
我想将一个“模板”文件的输出管道到MySQL中,该文件具有像${dbName}这样的变量。替换这些实例并将输出转储到标准输出的命令行实用程序是什么?
输入文件被认为是安全的,但是可能存在错误的替换定义。执行替换应避免执行意外的代码执行。
当前回答
这里有一个健壮的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控制字符,因为这些字符。在内部使用—因为函数处理文本,所以这应该是一个安全的假设。
其他回答
如果可以控制配置文件格式,则可以在bash中完成。您只需要源(“。”)配置文件,而不需要对其进行子shell。这确保了变量是在当前shell的上下文中创建的(并且继续存在),而不是在子shell中创建的(当子shell退出时,变量消失)。
$ 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
如果你的配置文件不是shell脚本,你可以在执行之前“编译”它(编译取决于你的输入格式)。
$ 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 '^$'
| 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
在你的具体情况下,你可以使用如下语句:
$ 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,瞧,希望你不会破坏你的数据库:-)。
我在想同样的事情时发现了这条线索。这启发了我(注意反节拍)
$ echo $MYTEST
pass!
$ cat FILE
hello $MYTEST world
$ eval echo `cat FILE`
hello pass! world
下面是一种让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是指定的环境变量。
envsubst
请不要用其他任何东西。不要eval)
我建议使用像Sigil这样的东西: https://github.com/gliderlabs/sigil
它被编译成一个二进制文件,所以在系统上安装它非常容易。
然后你可以像下面这样简单的一行代码:
cat my-file.conf.template | sigil -p $(env) > my-file.conf
这比eval更安全,比使用regex或sed更容易