Создание нового файла из шаблонов с помощью скрипта bash


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

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

Например:

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

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

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

7 40

7 ответов:

Вы можете сделать это с помощью 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

Модуль шаблона для 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
$ 

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

#!/bin/bash

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

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

foo=FOO bar=BAR ./template 

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

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

Было бы достаточно.

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

Для примера содержимого этих двух файлов, пожалуйста, обратитесь к https://serverfault.com/a/699377/120756 .

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

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

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.

Config:

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.

Вот как я сделал для себя:

. "${config_file}"
eval "cat << EOF
$(cat ${template_file})
EOF"

И если вы хотите поместить его в конфигурационный файл:

. "${config_file}"
eval "cat > /etc/MY_SERVICE/MY_CONFIG << EOF
$(cat ${template_file})
EOF"

Таким образом, вам не нужно создавать дополнительную переменную.

Вы можете использовать класс 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 устанавливает переменную окружения в нужное значение.