Шаблоны с Linux в сценарии оболочки?


26

то, что я хочу сделать, это:

1.) Наличие файла конфигурации в качестве шаблона с переменными, такими как $ version $ path (например, apache config)

2.) Наличие сценария оболочки, который «заполняет» переменные шаблона и записывает сгенерированный файл на диск.

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

Ответы:


23

Это очень возможно. Очень простой способ реализовать это - файл шаблона на самом деле является скриптом и использует переменные оболочки, такие как

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

Вы даже можете сделать это настраиваемым в командной строке, указав version=$1и path=$2, чтобы вы могли запустить его как bash script /foo/bar/baz 1.2.3. Значение -before EOF приводит к появлению пробела перед игнорированием строк, используйте plain, <<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

который заменил бы каждый экземпляр строк VERSION и PATH. Если есть другие причины, по которым эти строки будут в файле шаблона, вы можете выполнить поиск и замену на VERSION или% VERSION% или что-то менее вероятное случайное срабатывание.


18

Никаких инструментов, кроме /bin/sh. Дан файл шаблона формы

Version: ${version}
Path: ${path}

или даже со смешанным кодом оболочки

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)

и файл конфигурации, который можно разобрать

version="1.2.3-r42"
path="/some/place/under/the/rainbow/where/files/dance/in/happiness"
cost="42"

это просто, чтобы расширить это до

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

Действительно, учитывая путь к файлу конфигурации в переменной оболочки config_fileи путь к файлу шаблона template_file, все, что вам нужно сделать, это:

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

Возможно, это красивее, чем иметь полный скрипт оболочки в качестве файла шаблона (решение @ 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

Это выведет расширение на стандартный вывод; просто перенаправьте стандартный вывод в файл или измените вышеприведенное явно, чтобы получить желаемый выходной файл.

Предостережения: расширение файла шаблона не будет работать, если файл содержит неэкранированные двойные кавычки ( "). По соображениям безопасности, нам, вероятно, следует включить некоторые очевидные проверки работоспособности или, что еще лучше, выполнить преобразование без оболочки, если файл шаблона генерируется внешней сущностью.


1
Приятно видеть, как люди активно используют сценарии оболочки для таких забавных вещей. Мой приятель написал часы в сценарии оболочки. github.com/tablespoon/fun/blob/master/cli-clock Действительно забавные времена.
птенцы

2
Когда я нашел этот ответ , когда ищет , чтобы сделать это сам, я реализовал довольно наивный подход и отправил его на Github: github.com/nealian/bash-unsafe-templates
Pyrocater

9

Самый простой способ сделать это просто в Linux CLI - это использовать envsubstпеременные среды.

Пример файла шаблона apache.tmpl:

<VirtualHost *:${PORT}>
    ServerName ${SERVER_NAME}
    ServerAlias ${SERVER_ALIAS}
    DocumentRoot "${DOCUMENT_ROOT}"
</VirtualHost>

Запустите 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

Выход:

<VirtualHost *:443>
    ServerName example.com
    ServerAlias www.example.com
    DocumentRoot "/var/www/html/"
</VirtualHost>

2
Он является частью GNU gettext и поэтому доступен на всех основных платформах Unix (включая macOS X), а также в Microsoft Windows.
Трикасс

4

Вы, вероятно, должны изучить систему управления конфигурацией, например, Puppet или Chef . Они могут легко сделать то, что вы описали выше и многое другое.


1
Спасибо. Безусловно, у меня установлен и работает Chef. Но это добавляет много накладных расходов, когда вам приходится писать свои кулинарные книги. Я не знаю язык программирования ruby, и мой вывод был. это проще сделать с помощью сценария оболочки для более простых случаев (если это возможно).
Маркус

Похоже, Puppet и Chef оба используют ERB для шаблонов, и с этим просто смешно начинать. При заданной переменной nameстрока <%= name %>в шаблоне будет заменена nameзначением 's'. То, как вы определяете nameвне шаблона, очевидно, отличается между двумя системами.
Майк Ренфро

1
Да, создание шаблонов (с помощью Chef) абсолютно просто. Но использование chef в качестве фреймворка (и написание кулинарных книг) требует много времени. Чтобы получить данные в шаблоны, вам нужно понять, где и как Chef управляет «слиянием» источников данных и многих других вещей. Я начал писать свои собственные кулинарные книги, но сценарий оболочки в моем особом случае был бы в 100 раз быстрее ...
Маркус

Создание инфраструктуры для Chef или Puppet может быть болезненным, или вы можете попытаться выяснить, как управлять ими без головы, что является забавным приключением. Ansible прекрасно работает в режиме pull или push из коробки, так что он может найти лучший баланс, чтобы выяснить это и самостоятельно написать сценарий. docs.ansible.com/template_module.html
цыплята

4

Если вам нужны легкие и настоящие шаблоны, а не код оболочки, который генерирует новые файлы, обычно выбирайте sed& awkили perl. Вот одна ссылка: http://savvyadmin.com/generate-text-from-templates-scripts-and-csv-data/

Я бы использовал реальный язык, такой как perl, tcl, python, ruby ​​или что-то еще в этом классе. Нечто построенное для сценариев. Все они имеют хорошие, простые инструменты для создания шаблонов и множество примеров в Google.


4

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

Например, вы хотите сгенерировать / etc / network / interfaces из csv-файла, вы можете сделать это так:

Содержимое CSV-файла (здесь test.csv):

eth0;10.1.0.10;255.255.0.0;10.1.0.1
eth1;192.168.0.10; 255.255.255.0;192.168.0.1

Шаблон (здесь interfaces.tpl):

#% IFS=';'
#% while read "Val1" "Val2" "Val3" "Val4"; do
auto $Val1 
iface $Val1 inet static
  address $Val2 
  netmask $Val3 
  gateway $Val4 

#% done < "$CSVFILE"

Команда:

$ CSVFILE=test.csv sh -c "$( shtpl interfaces.tpl )"

Результат:

auto eth0 
iface eth0 inet static
  address 10.1.0.10 
  netmask 255.255.0.0 
  gateway 10.1.0.1 

auto eth1 
iface eth1 inet static
  address 192.168.0.10 
  netmask  255.255.255.0 
  gateway 192.168.0.1

Наслаждайтесь!


1

Я улучшил ответ FooF, чтобы пользователю не нужно было удалять двойные кавычки вручную:

#!/bin/bash
template="$(cat $1)"
template=$(sed 's/\([^\\]\)"/\1\\"/g; s/^"/\\"/g' <<< "$template")
eval "echo \"${template}\""

1

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

демонстрация печенья


Как это отвечает на вопрос?
Ральф Фридл

1
@RalfFriedl Я не уверен, что ты имеешь в виду. Я просто перечитал вопрос, думая, что, должно быть, что-то пропустил, но я этого не вижу. На самом деле, как это не отвечает ни на одну из частей вопроса, который был задан? Как будто я создал cookie-файл с единственной целью ответить на этот вопрос ... что я и сделал, хотя, возможно, в то время я думал об этом немного иначе. :)
Брайан Бугий,

Я немного опаздываю, чтобы играть посредника, но, возможно, Ральф просто мягко побуждал вас объяснить, как cookie отвечает на вопрос, вместо того, чтобы недвусмысленно предположить, что вы недостаточно хорошо знаете свой собственный проект, чтобы судить, может ли он решить чью-то проблему ,
Abathur

0

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

Допустим, у вас есть это file.template:

# My template
## Author
 - @NAME@ <@EMAIL@>

И этот rulesфайл:

NAME=LEOPOLDO WINSTON
EMAIL=leothewinston\@leoserver.com

Вы выполняете эту команду:

templater rules < file.template

Вы получаете это:

# My template
## Author
 - LEOPOLDO WINSTON <leothewinston@leoserver.com>

Вы можете установить его:

 bpkg install vicentebolea/bash-templater

Это сайт проекта


0

Чтобы расширить великолепный ответ @ FooF (строки не форматируются в комментариях), используя heredoc + управляющие символы, вы можете разрешить произвольные символы и имена файлов:

template() {
    # if [ "$#" -eq 0 ] ; then return; fi # or just error
    eval "cat <<$(printf '\x04\x04\x04');
$(cat $1)
"
}

Это принимает любой ненулевой символ и усекает только рано, если 3 ^Dбайта встречаются в их собственной строке (реально никогда). Zsh даже поддерживает нулевые терминаторы, так printf '\x00\x00\x00'что будет работать. templateдаже работает для коварных имен файлов, таких как:

for num in `seq 10`; do
    template 'foo "$ .html' # works
done

Осторожно, шаблоны оболочки могут «расширять» произвольные команды, например $(launch_nukes.sh --target $(curl -sL https://freegeoip.app/csv/ | cut -d, -f 9,10)). С большой силой ...

Редактировать: если вы действительно не хотите, чтобы ваши файлы запускали ядерное оружие, просто sudo -u nobody sh(или другого безопасного пользователя) заранее.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.