【问题标题】:Template variable replacements only. Is text/Template a good fit?仅模板变量替换。文本/模板是否合适?
【发布时间】:2015-08-26 02:01:29
【问题描述】:

我正在寻找一种有效的方法来替换用户提供的文本文件中的一堆占位符/标记,并将它们的相应值存储在简单的地图或环境变量中。问题是模板文件将由最终用户提供,所以我正在寻找一种“安全”的方式来只进行变量替换,而不会有任何代码执行风险等。

Go 的标准“文本/模板”将适用于替换本身,但会施加特定的格式要求(例如,在 Key 之前添加点“.”)并通过其函数调用、管道等打开其他可能性。

因此,理想情况下,我正在寻找一个可以解析具有可配置分隔符(“{{}}”或“${}”或“$##$”)的文本文件并替换所有通过查找提供的地图或其 env var 值检测到的令牌。类似于 Python 的 string.Template (https://docs.python.org/2.6/library/string.html?highlight=string.template#string.Template) 所做的。

是否有一种简单的方法可以为此配置或重用文本/模板库?还有其他更适合用例的方法吗?我也研究了非 golang 选项(例如 envsubtrawksed 脚​​本等),所以如果有更好的选择,请随意离开 Go。

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

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

输入数据示例:

VAR_1 = apples
VAR_2 = oranges

处理后的预期输出:

var1=apples
var2=oranges

【问题讨论】:

  • 您可以手动读取文件并对变量/替换执行连续的替换操作,并且您可以通过即时构建输出来有效地执行此操作。只需几行代码(约 30 行)即可完成。请参阅此问题+答案,该问题在 Java 中显示:Alternative to successive String.replace
  • 谢谢 icza。实现我自己的替换器绝对是一种选择,但我希望找到一个可以做到这一点的高效灵活的库。替换字符串中的标记似乎是一项足够通用的任务,其他人早就可以解决了。
  • Mustache 这样的东西适合你吗?
  • n0741337,小胡子是个不错的选择。我没想过要寻找 Go 实现。但是,它仍然支持“Sections”,语法类似于{{#。你知道是否有办法禁用那块吗?
  • 您可以预先过滤输入(无论如何都是好主意),如果它包含 {{# 则拒绝它

标签: python awk sed go go-templates


【解决方案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

请注意,由于 ENVIRON,这是 gawk 特有的,并且需要在命令行上导出或设置 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

【讨论】:

  • 感谢 sn-p @EdMorton。我目前在数据结构(在 Go 或 Python 程序中)或环境变量中拥有源 var/values。我可以将 var 数据写入临时文件,以便按建议工作。是否有一种简单的方法可以“传入”数据或让 awk 脚本从导出的 shell 环境变量中查找它,而无需使用它创建临时文件?
  • 抱歉,我从未听说过“Go”,也无法从地里的一个洞中分辨出 Python 程序。当您说“env vars”时-您是在谈论shell变量还是其他东西?无论是什么,请编辑您的问题以显示它。
  • 再次感谢@EdMorton。这看起来是一个很好的、务实的方法。我没有想过在命令行中传递 var 名称,但它很容易以编程方式完成,并且还有助于作为输入过滤器。我将使用几个真实世界的模板文件对其进行测试并报告回来。
【解决方案2】:

只需使用 fasttemplate[1]。它完全符合您的要求:

  • 可以使用任意占位符的开始和结束分隔符。
  • 不可信输入的风险为零,因为除了占位符替换之外没有任何逻辑。
  • 工作速度比文本/模板快得多(提高 10 倍)。

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

【讨论】:

    猜你喜欢
    • 2021-08-15
    • 2018-02-06
    • 1970-01-01
    • 2023-04-04
    • 2012-09-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多