在 Shell 脚本中使用 Linux 进行模板化?

Mar*_*kus 41 linux shell

我想要完成的是:

1.) 有一个配置文件作为模板,带有像 $version $path 这样的变量(例如 apache config)

2.) 有一个 shell 脚本来“填充”模板的变量并将生成的文件写入磁盘。

这是否可以通过 shell 脚本实现。如果您能说出一些我可以完成的命令/工具或一些好的链接,我将非常感激。

小智 34

在 Linux CLI 中执行此操作的最简单方法是使用envsubst环境变量。

示例模板文件apache.tmpl

<VirtualHost *:${PORT}>
    ServerName ${SERVER_NAME}
    ServerAlias ${SERVER_ALIAS}
    DocumentRoot "${DOCUMENT_ROOT}"
</VirtualHost>
Run Code Online (Sandbox Code Playgroud)

运行envsubst并将结果输出到新文件my_apache_site.conf

export PORT="443"
export SERVER_NAME="example.com"
export SERVER_ALIAS="www.example.com"
export DOCUMENT_ROOT="/var/www/html/"
envsubst < apache.tmpl > my_apache_site.conf
Run Code Online (Sandbox Code Playgroud)

输出:

<VirtualHost *:443>
    ServerName example.com
    ServerAlias www.example.com
    DocumentRoot "/var/www/html/"
</VirtualHost>
Run Code Online (Sandbox Code Playgroud)

  • 它是 GNU gettext 的一部分,因此可用于所有主要 Unix 平台(包括 macOS X)以及 Microsoft Windows。 (6认同)

mti*_*erg 30

这是很有可能的。实现这一点的一个非常简单的方法是让模板文件实际上是脚本并使用 shell 变量,例如

#! /bin/bash
version="1.2.3"
path="/foo/bar/baz"
cat > /tmp/destfile <<-EOF
here is some config for version $version which should
also reference this path $path
EOF
Run Code Online (Sandbox Code Playgroud)

您甚至可以通过指定version=$1and在命令行上进行配置path=$2,这样您就可以像bash script /foo/bar/baz 1.2.3. 该-EOF造成的空白行被忽略之前之前,使用普通的<<EOF,如果你不希望这样的行为。

另一种方法是使用 sed 的搜索和替换功能

#! /bin/bash
version="1.2.3"
path="/foo/bar/baz"
sed -e "s/VERSION/$version/g" -e "s/PATH/$path/" /path/to/templatefile > /tmp/destfile
Run Code Online (Sandbox Code Playgroud)

这将替换字符串 VERSION 和 PATH 的每个实例。如果由于其他原因这些字符串会出现在模板文件中,您可能会搜索并替换为VERSION或 %VERSION% 或不太可能被意外触发的内容。


Foo*_*ooF 24

除了/bin/sh. 给定表单的模板文件

Version: ${version}
Path: ${path}
Run Code Online (Sandbox Code Playgroud)

甚至包含混合的 shell 代码

Version: ${version}
Path: ${path}
Cost: ${cost}\$
$(i=1; for w in one two three four; do echo Param${i}: ${w}; i=$(expr $i + 1); done)
Run Code Online (Sandbox Code Playgroud)

和一个 shell 可解析的配置文件,如

version="1.2.3-r42"
path="/some/place/under/the/rainbow/where/files/dance/in/happiness"
cost="42"
Run Code Online (Sandbox Code Playgroud)

将其扩展到

Version: 1.2.3-r42
Path: /some/place/under/the/rainbow/where/files/dance/in/happiness
Cost: 42$
Param1: one
Param2: two
Param3: three
Param4: four
Run Code Online (Sandbox Code Playgroud)

实际上,给定 shell 变量中配置文件config_file的路径和 中模板文件的路径template_file,您需要做的就是:

. ${config_file}
template="$(cat ${template_file})"
eval "echo \"${template}\""
Run Code Online (Sandbox Code Playgroud)

这可能比将完整的 shell 脚本作为模板文件(@mtinberg 的解决方案)更漂亮。

完整的原始模板扩展程序:

#!/bin/sh

PROG=$(basename $0)

usage()
{
    echo "${PROG} <template-file> [ <config-file> ]"
}

expand()
{
    local template="$(cat $1)"
    eval "echo \"${template}\""
}

case $# in
    1) expand "$1";;
    2) . "$2"; expand "$1";;
    *) usage; exit 0;;
esac
Run Code Online (Sandbox Code Playgroud)

这会将扩展输出到标准输出;只需将标准输出重定向到文件或以明显的方式修改上述内容即可生成所需的输出文件。

注意事项:如果文件包含未转义的双引号 ( "),则模板文件扩展将不起作用。出于安全原因,我们可能应该包括一些明显的健全性检查,或者更好的是,如果模板文件是由外部实体生成的,则执行 shell 转义转换。

  • 很高兴仍然看到人们积极使用 shell 脚本来做这样有趣的事情。我的一个朋友用shell脚本写了一个时钟。https://github.com/tablespoon/fun/blob/master/cli-clock 确实很有趣。 (2认同)
  • 当我自己找这个答案时,我实现了非常幼稚的方法并将其发布在 Github 上:https://github.com/nealian/bash-unsafe-templates (2认同)

Mar*_*ark 5

如果您想要轻量级且真实的模板而不是生成新文件的 shell 代码,通常的选择是sed&awkperl。这是一个链接:http://savvyadmin.com/generate-text-from-templates-scripts-and-csv-data/

对我来说,我会使用真正的语言,如 perl、tcl、python、ruby 或该课程中的其他语言。为脚本编写而构建的东西。他们都有很好、简单的模板工具,并且在谷歌上有大量的例子。