Создать новый файл из шаблонов с помощью скрипта bash - PullRequest
44 голосов
/ 02 июня 2011

Я должен создать файлы conf и init.d, которые очень похожи.Эти файлы позволяют развернуть новый http сервис на моих серверах.Эти файлы одинаковы, и только некоторые параметры меняются от одного файла к другому (listen_port, домен, путь на сервере ...).

Поскольку любая ошибка в этих файлах приводит к сбою службы, я хотел бычтобы создать эти файлы, используя скрипт bash.

Например:

generate_new_http_service.sh 8282 subdomain.domain.com /home/myapp/rootOfHTTPService

Я ищу некий шаблонный модуль, который я мог бы использовать с bash.Этот шаблонный модуль будет использовать некоторые общие сценарии conf и init.d для создания новых.

У вас есть намеки на это?Если бы не я, я мог бы использовать шаблонизатор Python.

Ответы [ 9 ]

71 голосов
/ 02 июня 2011

Вы можете сделать это, используя 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

Вывод:

$ generate.sh 8080 domain.com

This is my template.
Port is 8080
Domain is domain.com

или сохранить его в файл:

$ generate.sh 8080 domain.com > result
41 голосов
/ 02 июня 2011

Шаблон модуля для 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
$ 
20 голосов
/ 02 июня 2011

вы можете сделать это прямо в bash, вам даже не нужен sed. Напишите такой скрипт:

#!/bin/bash

cat <<END
this is a template
with $foo
and $bar
END

тогда назовите это так:

foo=FOO bar=BAR ./template 
11 голосов
/ 16 июня 2015

Для простой генерации файлов, в основном делает

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

будет достаточно.

Здесь ${config_file} содержит переменные конфигурации в разбираемом формате оболочки, а ${template_file} - файл шаблона, который выглядит как документ оболочки здесь. Первая строка находится в файле ${config_file}, вторая строка помещает содержимое файла ${template_file} в переменную оболочки template_str. Наконец, в третьей строке мы строим команду оболочки echo "${template_str}" (где расширенное выражение "${template_str}" в двойных кавычках) и оцениваем ее.

Пример содержимого этих двух файлов см. В https://serverfault.com/a/699377/120756.

.

Существуют ограничения, которые вы можете иметь в файле шаблона или вам нужно выполнить экранирование оболочки. Кроме того, если файл шаблона создается извне, то по соображениям безопасности вам следует рассмотреть возможность применения надлежащей фильтрации перед выполнением, чтобы, например, вы не потеряли свои файлы, когда кто-то вставит знаменитый $(rm -rf /) в файл шаблона.

5 голосов
/ 06 февраля 2018

Вот подход, который я решил использовать для решения этой проблемы. Я нашел его немного более гибким, чем некоторые из вышеуказанных подходов, и он позволяет избежать некоторых проблем с кавычками.

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"

шаблон:

Template full of important %THINGS%

"Note that quoted %FIELDS% are handled correctly"

If I need %NEWLINES% then I can add them as well.

конфиг:

THINGS=stuff
FIELDS="values work too!"
NEWLINES="those\\nnifty\\nlinebreaks"

результат: Шаблон полон важных вещей

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

If I need those
nifty
linebreaks then I can add them as well.
3 голосов
/ 07 октября 2015

[Редактировать] Я изменил свой ответ с исходного, который был несколько лет назад.

Мне нравится ответ от FooF выше: https://stackoverflow.com/a/30872526/3538173

Тем не менее, я предпочитаю не иметь промежуточную переменную для хранения всего содержимого файла шаблона в памяти.

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

Пример

Создать файл шаблона. Давайте назовем это example.tpl:

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

Создайте файл конфигурации для хранения ваших переменных. Давайте назовем это good.conf:

NAME=John
WEATHER=good

Теперь в скрипте, где вы хотите отобразить шаблон, вы можете написать это:

#!/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

Вы должны увидеть этот замечательный вывод:)

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

Осторожно с eval

Когда вы используете eval, если файл шаблона содержит некоторые инструкции, они будут выполнены, и это может быть опасно. Например, давайте изменим example.tpl выше с этим содержанием:

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

I'm a hacker, hu hu! Look, fool!
$(ls /)

Теперь, если вы создадите файл шаблона, вы увидите следующее:

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

Теперь отредактируйте ваш файл good.conf, чтобы иметь этот контент:

NAME=$(ls -l /var)
WEATHER=good

и отрендерить шаблон. Вы должны увидеть что-то вроде этого:

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

Как вы можете видеть, внедрение команды в файле конфигурации и файле шаблона возможно, и поэтому вы должны быть особенно осторожны:

  • быть уверенным в содержимом файла шаблона : проверить, что команда НЕ вводится.
  • быть уверенным в содержимом файла конфигурации : убедитесь, что нет команды ввода. Если файл конфигурации исходит от кого-то другого, вам необходимо знать и доверять этому человеку перед обработкой шаблона.

Представьте, что вы sudoer без пароля, рендеринг файла шаблона может привести к разрушению вашей системы с удачным размещением rm -rf.

Пока вы контролируете содержимое этих файлов, можно использовать этот шаблон eval.

Если у вас есть внешний (ненадежный) входящий файл конфигурации, вы должны искать шаблонизатор, который изолирует этот тип инъекций. Например, шаблон Jinja2 довольно известен в Python.

1 голос
/ 05 января 2019

Элегантное и короткое решение в одной строке с perl

Я использую perl для замены переменных на их значения:

export world=World beautiful=wonderful
echo 'I love you, $world! You are $beautiful.' >my_template.txt
perl -pe 's|\$([A-Za-z_]+)|$ENV{$1}|g' my_template.txt

Выход: I love you, World! You are wonderful.

my_template.txt может содержать переменные с префиксом $.

0 голосов
/ 14 ноября 2018

Я недавно опубликовал проект bash, который выполняет только этот, используя jinja-подобный шаблонный синтаксис.Это называется cookie .Вот демо:

cookie demo

0 голосов
/ 13 февраля 2016

Вы можете использовать класс Python string.Template

$ echo 'before $X after' > template.txt

$ python  -c 'import string; print(string.Template(open("template.txt").read()).substitute({"X":"A"}))'

before A after

или

$  python  -c 'import string, sys; print(string.Template(open("template.txt").read()).substitute({"X":sys.argv[1]}))' "A"

Здесь $X является заполнителем в шаблоне, а {"X":"A"} является отображением заполнителяк значению.В коде Python мы читаем текст шаблона из файла, создаем из него шаблон, а затем подставляем заполнитель в аргумент командной строки.

В качестве альтернативы вы можете использовать ERB Ruby, если Ruby установлен на вашем компьютере.

$ echo "before <%= ENV['X'] %> after" > template.txt

$ X=A erb template.txt

before A after

Здесь <%= ENV['X'] %> является заполнителем.ENV['X'] читает значение из переменной среды.X=A устанавливает переменную окружения на желаемое значение.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...