模板变量替换而已。文本/模板是否适合?

huangapple go评论85阅读模式
英文:

Template variable replacements only. Is text/Template a good fit?

问题

我正在寻找一种有效的方法来替换用户提供的文本文件中的一系列占位符/标记,将它们替换为存储在简单映射或环境变量中的相应值。问题在于模板文件将由最终用户提供,因此我正在寻找一种“安全”的方法,仅进行变量替换,而不会有任何代码执行等风险。

Go的标准“text/template”可以用于替换本身,但它对格式有特定要求(例如,在键之前需要点“.”),并且通过其函数调用、管道等功能打开了其他可能性。

因此,理想情况下,我希望有一个函数,可以解析具有可配置分隔符(“{{}}”或“${}”或“$##$”)的文本文件,并将所有检测到的标记替换为查找提供的映射或它们的环境变量值。类似于Python的string.Template所做的操作。

是否有一种简单的方法可以配置或重用text/template库来实现这一点?是否有其他方法更适合这种用例?我也研究了非Go语言的选项(如envsubtrawksed脚本等),所以如果有更好的解决方案,请随意提供。

示例输入文件('template.properties'):

var1=$#VAR_1#$
var2=$#VAR_2#$

示例输入数据:

VAR_1 = apples
VAR_2 = oranges

处理后的预期输出:

var1=apples
var2=oranges
英文:

I'm looking for an efficient way to replace a bunch of placeholders/tokens in a user supplied text file, with their corresponding values stored in a simple map or environment vars. The thing is that the template file will be supplied by the end user, so I'm looking for a "safe" way to do only the variable replacements, without any risk of code execution, etc.

Go's standard "text/template" would work for the replacement itself but imposes specific formatting requirements (e.g. dot "." before the Key) and opens up other possibilities with its function invocations, pipelines, etc.

So what I'm looking for, ideally, is a function that can parse a text file with configurable delimiters ("{{}}" or "${}" or "$##$") and replace all the detected tokens with lookups into a supplied map or their env var values. Similar to what Python's string.Template (https://docs.python.org/2.6/library/string.html?highlight=string.template#string.Template) does.

Is there an easy way to configure or reuse the text/template library for this? Are there any other approaches that would fit the use case better? I've looked into non-golang options as well (like envsubtr, awk and sed scripts etc.) so feel free to go outside of Go if something fits better.

Sample input file ('template.properties'):

var1=$#VAR_1#$
var2=$#VAR_2#$

Sample input data:

VAR_1 = apples
VAR_2 = oranges

Expected output after processing:

var1=apples
var2=oranges

答案1

得分: 1

只返回翻译的部分:

只要您的变量名不包含ERE元字符,这将起作用:

$ cat tst.awk
NR==FNR { var2val[$1] = $NF; next }
{
    for (var in var2val) {
        sub("[$]#"var"#[$]",var2val[var])
    }
    print
}

$ awk -f tst.awk input.data template.properties
var1=apples
var2=oranges

关于您在下面的评论中提到的将映射存储在变量中而不是在input.data中,这可能是您要找的:

$ cat tst.awk
BEGIN {
    split(vars,tmp)
    for (i in tmp) {
        var2val[tmp[i]] = ENVIRON[tmp[i]]
    }
}
{
    for (var in var2val) {
        sub("[$]#"var"#[$]",var2val[var])
    }
    print
}

将与shell变量一起使用,例如:

$ VAR_1=apples VAR_2=oranges gawk -v vars="VAR_1 VAR_2" -f tst.awk template.properties
var1=apples
var2=oranges

或者:

$ export VAR_1=apples
$ export VAR_2=oranges
$ gawk -v vars="VAR_1 VAR_2" -f tst.awk template.properties
var1=apples
var2=oranges

或者:

$ VAR_1=apples
$ VAR_2=oranges
$ VAR_1="$VAR_1" VAR_2="$VAR_2" gawk -v vars="VAR_1 VAR_2" -f tst.awk template.properties
var1=apples
var2=oranges

请注意,这是特定于gawk的,由于ENVIRON的存在,需要将VAR_1等导出或在命令行上设置,就像我上面所示的那样。

或者也许这是您想要的:

$ cat tst.awk
BEGIN {
    var2val["VAR_1"] = VAR_1
    var2val["VAR_2"] = VAR_2
}
{
    for (var in var2val) {
        sub("[$]#"var"#[$]",var2val[var])
    }
    print
}

$ VAR_1=apples
$ VAR_2=oranges
$ awk -v VAR_1="$VAR_1" -v VAR_2="$VAR_2" -f tst.awk template.properties
var1=apples
var2=oranges
英文:

This will work as long as your variable names don't contain ERE metacharacters:

$ cat tst.awk
NR==FNR { var2val[$1] = $NF; next }
{
    for (var in var2val) {
        sub("[$]#"var"#[$]",var2val[var])
    }
    print
}

$ awk -f tst.awk input.data template.properties
var1=apples
var2=oranges

wrt your comment below about having the mappings in variables instead of in input.data, this might be what you're looking for:

$ cat tst.awk
BEGIN {
    split(vars,tmp)
    for (i in tmp) {
        var2val[tmp[i]] = ENVIRON[tmp[i]]
    }
}
{
    for (var in var2val) {
        sub("[$]#"var"#[$]",var2val[var])
    }
    print
}

will work with shell variables like:

$ VAR_1=apples VAR_2=oranges gawk -v vars="VAR_1 VAR_2" -f tst.awk template.properties
var1=apples
var2=oranges

or:

$ export VAR_1=apples
$ export VAR_2=oranges
$ gawk -v vars="VAR_1 VAR_2" -f tst.awk template.properties
var1=apples
var2=oranges

or:

$ VAR_1=apples
$ VAR_2=oranges
$ VAR_1="$VAR_1" VAR_2="$VAR_2" gawk -v vars="VAR_1 VAR_2" -f tst.awk template.properties
var1=apples
var2=oranges

Note that this is gawk-specific due to ENVIRON and requires VAR_1 etc. to be exported or set on the command line as I have it above.

Or maybe this is what you want:

$ cat tst.awk
BEGIN {
    var2val["VAR_1"] = VAR_1
    var2val["VAR_2"] = VAR_2
}
{
    for (var in var2val) {
        sub("[$]#"var"#[$]",var2val[var])
    }
    print
}

$ VAR_1=apples
$ VAR_2=oranges
$ awk -v VAR_1="$VAR_1" -v VAR_2="$VAR_2" -f tst.awk template.properties
var1=apples
var2=oranges

答案2

得分: 0

只需使用fasttemplate1。它完全符合您的要求:

  • 可以使用任意占位符的起始和结束分隔符。
  • 对于不受信任的输入没有任何逻辑,因为只有占位符的替换。
  • 比text/template快得多(快10倍)。

1https://github.com/valyala/fasttemplate

英文:

Just use fasttemplate1. It perfectly fits your requirements:

  • Arbitrary placeholders' start and end delimiters can be used.
  • Zero risk for untrusted input, because there is no any logic except placeholders' substitution.
  • Works much faster than text/template (by 10x).

1https://github.com/valyala/fasttemplate

huangapple
  • 本文由 发表于 2015年6月11日 00:59:52
  • 转载请务必保留本文链接:https://go.coder-hub.com/30762761.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定