使用bash脚本从模板创建新文件

khe*_*aud 46 bash configuration templates template-engine

我必须创建conf文件,init.d它们非常相似.这些文件允许在我的服务器上部署新的http服务.这些文件是相同的,只有一些参数从一个文件更改为另一个文件(listen_port域,服务器上的路径......).

由于这些文件中的任何错误都会导致服务错误,我想使用bash脚本创建这些文件.

例如:

generate_new_http_service.sh 8282 subdomain.domain.com /home/myapp/rootOfHTTPService
Run Code Online (Sandbox Code Playgroud)

我正在寻找一种可以与bash一起使用的模板模块.这个模板模块将使用一些通用的conf和init.d脚本来创建新的脚本.

你有提示吗?如果不是,我可以使用python模板引擎.

dog*_*ane 77

你可以使用heredoc来做到这一点.例如

generate.sh:

#!/bin/sh

#define parameters which are passed in.
PORT=$1
DOMAIN=$2

#define the template.
cat  << EOF
This is my template.
Port is $PORT
Domain is $DOMAIN
EOF
Run Code Online (Sandbox Code Playgroud)

输出:

$ generate.sh 8080 domain.com

This is my template.
Port is 8080
Domain is domain.com
Run Code Online (Sandbox Code Playgroud)

或将其保存到文件:

$ generate.sh 8080 domain.com > result
Run Code Online (Sandbox Code Playgroud)

  • heredoc中的文件可以是一个单独的文件吗? (4认同)
  • 很容易。这个技巧的名字是“eval”。看我的回答。 (2认同)

小智 42

bash的模板模块?使用sed,卢克!以下是数百万种可能的方法之一的示例:

$ cat template.txt 
#!/bin/sh

echo Hello, I am a server running from %DIR% and listening for connection at %HOST% on port %PORT% and my configuration file is %DIR%/server.conf

$ cat create.sh 
#!/bin/sh

sed -e "s;%PORT%;$1;g" -e "s;%HOST%;$2;g" -e "s;%DIR%;$3;g" template.txt > script.sh

$ bash ./create.sh 1986 example.com /tmp
$ bash ./script.sh 
Hello, I am a server running from /tmp and listening for connection at example.com on port 1986 and my configuration file is /tmp/server.conf
$ 
Run Code Online (Sandbox Code Playgroud)

  • 这种方法一般存在问题。例如,如果`$1` 值包含`%HOST%`,那么第二次替换将无意中替换它。所以我建议使用另一种方法。 (2认同)

Kim*_*bel 21

你可以直接在bash中这样做,你甚至不需要sed.写一个这样的脚本:

#!/bin/bash

cat <<END
this is a template
with $foo
and $bar
END
Run Code Online (Sandbox Code Playgroud)

然后像这样称呼它:

foo=FOO bar=BAR ./template 
Run Code Online (Sandbox Code Playgroud)


Foo*_*ooF 11

对于简单的文件生成,基本上做

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

就够了

这里${config_file}包含shell可解析格式的配置变量,并且${template_file}是看起来像shell here文档的模板文件.文件中的第一行源${config_file},第二行将文件的内容${template_file}放入shell变量中template_str.最后在第三行中我们构建了shell命令echo "${template_str}"("${template_str}"扩展了双引号表达式)并对其进行了评估.

有关这两个文件内容的示例,请参阅https://serverfault.com/a/699377/120756.

您可以在模板文件中拥有限制,或者需要执行shell转义.此外,如果模板文件是外部生成的,那么出于安全原因,您需要考虑在执行之前实施适当的过滤,这样当有人$(rm -rf /)在模板文件中注入着名文件时,您就不会丢失文件.


Sam*_*han 7

[编辑] 我从几年前的原始答案中更改了我的答案。

我喜欢上面 FooF 的答案:https ://stackoverflow.com/a/30872526/3538173

然而,我不希望有一个中间变量来将模板文件的全部内容存储在内存中。

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

例子

创建模板文件。让我们称之为example.tpl

Hello, ${NAME}!
Today, the weather is ${WEATHER}. Enjoy!
Run Code Online (Sandbox Code Playgroud)

创建一个配置文件来存储您的变量。让我们称之为good.conf

NAME=John
WEATHER=good
Run Code Online (Sandbox Code Playgroud)

现在,在要渲染模板的脚本中,您可以这样写:

#!/usr/bin/env bash

template_file=example.tpl
config_file=good.conf

. "${config_file}"
eval "echo \"$(cat "${template_file}")\""

# Or store the output in a file
eval "echo \"$(cat "${template_file}")\"" > out
Run Code Online (Sandbox Code Playgroud)

你应该看到这个美妙的输出:)

Hello, John!
Today, the weather is good. Enjoy!
Run Code Online (Sandbox Code Playgroud)

小心与 eval

当您使用 时eval,如果模板文件包含一些指令,它们将被执行,并且可能是危险的。例如,让我们example.tpl用以下内容更改上面的内容:

Hello, ${NAME}!
Today, the weather is ${WEATHER}. Enjoy!

I'm a hacker, hu hu! Look, fool!
$(ls /)
Run Code Online (Sandbox Code Playgroud)

现在,如果您渲染模板文件,您将看到:

Hello, John!
Today, the weather is good. Enjoy!

I'm a hacker, hu hu! Look, fool!
bin
boot
dev
etc
home
lib
lib64
media
mnt
opt
proc
root
run
sbin
srv
sys
tmp
usr
var
Run Code Online (Sandbox Code Playgroud)

现在编辑您的文件good.conf以包含以下内容:

NAME=$(ls -l /var)
WEATHER=good
Run Code Online (Sandbox Code Playgroud)

并渲染模板。您应该会看到如下内容:

Hello, total 8
drwxr-xr-x.  2 root root    6 Apr 11 04:59 adm
drwxr-xr-x.  5 root root   44 Sep 11 18:04 cache
drwxr-xr-x.  3 root root   34 Sep 11 18:04 db
drwxr-xr-x.  3 root root   18 Sep 11 18:04 empty
drwxr-xr-x.  2 root root    6 Apr 11 04:59 games
drwxr-xr-x.  2 root root    6 Apr 11 04:59 gopher
drwxr-xr-x.  3 root root   18 May  9 13:48 kerberos
drwxr-xr-x. 28 root root 4096 Oct  8 00:30 lib
drwxr-xr-x.  2 root root    6 Apr 11 04:59 local
lrwxrwxrwx.  1 root root   11 Sep 11 18:03 lock -> ../run/lock
drwxr-xr-x.  8 root root 4096 Oct  8 04:55 log
lrwxrwxrwx.  1 root root   10 Sep 11 18:03 mail -> spool/mail
drwxr-xr-x.  2 root root    6 Apr 11 04:59 nis
drwxr-xr-x.  2 root root    6 Apr 11 04:59 opt
drwxr-xr-x.  2 root root    6 Apr 11 04:59 preserve
lrwxrwxrwx.  1 root root    6 Sep 11 18:03 run -> ../run
drwxr-xr-x.  8 root root   87 Sep 11 18:04 spool
drwxrwxrwt.  4 root root  111 Oct  9 09:02 tmp
drwxr-xr-x.  2 root root    6 Apr 11 04:59 yp!
Today, the weather is good. Enjoy!

I'm a hacker, hu hu! Look, fool!
bin
boot
dev
etc
home
lib
lib64
media
mnt
opt
proc
root
run
sbin
srv
swapfile
sys
tmp
usr
var
Run Code Online (Sandbox Code Playgroud)

如您所见,配置文件模板文件中的命令注入是可能的,这就是您必须格外小心的原因:

  • 确保模板文件的内容:检查是否没有命令注入。
  • 确保配置文件的内容:检查是否也没有命令注入。如果配置文件来自其他人,您需要在渲染模板之前了解并信任该人。

想象一下,你是一个没有密码的 sudoer,渲染模板文件可能会导致你的系统被一个放置良好的rm -rf.

只要您控制这些文件的内容,就可以使用此eval模板。

如果您有一个外部(不受信任的)传入配置文件,您应该寻找模板引擎,它将隔离这些类型的注入。例如,Jinja2 模板在 Python 中非常有名。


小智 5

这是我最终解决这个问题的方法.我发现它比上面的一些方法更灵活,它避免了一些引号问题.

fill.sh:

#!/usr/bin/env sh

config="$1"
template="$2"
destination="$3"

cp "$template" "$destination"

while read line; do
    setting="$( echo "$line" | cut -d '=' -f 1 )"
    value="$( echo "$line" | cut -d '=' -f 2- )"

    sed -i -e "s;%${setting}%;${value};g" "$destination"
done < "$config"
Run Code Online (Sandbox Code Playgroud)

模板:

Template full of important %THINGS%

"Note that quoted %FIELDS% are handled correctly"

If I need %NEWLINES% then I can add them as well.
Run Code Online (Sandbox Code Playgroud)

配置:

THINGS=stuff
FIELDS="values work too!"
NEWLINES="those\\nnifty\\nlinebreaks"
Run Code Online (Sandbox Code Playgroud)

结果: 模板充满了重要的东西

"Note that quoted "values work too!" are handled correctly"

If I need those
nifty
linebreaks then I can add them as well.
Run Code Online (Sandbox Code Playgroud)