Шаблонная обработка Bash: Как в файлы конфигурации сборки из шаблонов с Bash?

Я пишу сценарий для автоматизации конфигурационных файлов создания для Apache и PHP для моего собственного веб-сервера. Я не хочу использовать любые графический интерфейсы пользователя как CPanel или ISPConfig.

У меня есть некоторые шаблоны Apache и конфигурационных файлов PHP. Сценарий Bash должен считать шаблоны, превратить подстановку переменных и произвести проанализированные шаблоны в некоторую папку. Что лучший способ состоит в том, чтобы сделать это? Я могу думать о нескольких путях. Какой является лучшим или может быть существуют некоторые лучшие способы сделать это? Я хочу сделать это в чистом Bash (это легко в PHP, например),

1) Как заменить $ {} заполнители в текстовом файле?

template.txt:

the number is ${i}
the word is ${word}

script.sh:

#!/bin/sh

#set variables
i=1
word="dog"
#read in template one line at the time, and replace variables
#(more natural (and efficient) way, thanks to Jonathan Leffler)
while read line
do
    eval echo "$line"
done < "./template.txt"

BTW, как я перенаправляю вывод во внешний файл здесь? Я должен выйти из чего-то, если переменные содержат, скажем, кавычки?

2) Используя кошку и sed для замены каждой переменной с ее значением:

Учитывая template.txt:

The number is ${i}
The word is ${word}

Команда:

cat template.txt | sed -e "s/\${i}/1/" | sed -e "s/\${word}/dog/"

Кажется плохим мне из-за потребности выйти из многих различных символов, и со многими переменными строка будет tooooo долго.

Можно ли думать о некотором другом изящном и безопасном решении?

116
задан Community 23 May 2017 в 12:34
поделиться

3 ответа

Вы можете использовать это:

perl -p -i -e 's/\$\{([^}]+)\}/defined $ENV{$1} ? $ENV{$1} : $&/eg' < template.txt

для замены всех ${...} строк на соответствующие переменные окружения (не забудьте экспортировать их перед запуском этого скрипта).

Для чистого bash это должно работать (при условии, что переменные не содержат строк ${...}):

#!/bin/bash
while read -r line ; do
    while [[ "$line" =~ (\$\{[a-zA-Z_][a-zA-Z_0-9]*\}) ]] ; do
        LHS=${BASH_REMATCH[1]}
        RHS="$(eval echo "\"$LHS\"")"
        line=${line//$LHS/$RHS}
    done
    echo "$line"
done

. Решение, которое не зависает, если RHS ссылается на какую-то переменную, которая ссылается сама на себя:

#!/bin/bash
line="$(cat; echo -n a)"
end_offset=${#line}
while [[ "${line:0:$end_offset}" =~ (.*)(\$\{([a-zA-Z_][a-zA-Z_0-9]*)\})(.*) ]] ; do
    PRE="${BASH_REMATCH[1]}"
    POST="${BASH_REMATCH[4]}${line:$end_offset:${#line}}"
    VARNAME="${BASH_REMATCH[3]}"
    eval 'VARVAL="$'$VARNAME'"'
    line="$PRE$VARVAL$POST"
    end_offset=${#PRE}
done
echo -n "${line:0:-1}"

WARNING: Я не знаю способа корректной обработки ввода с NUL в bash или сохранения количества новых строк в конце строки. Последний вариант представлен так, как он есть, потому что оболочки "любят" двоичный ввод:

  1. read будет интерпретировать обратные слеши.
  2. read -r не будет интерпретировать обратные слеши, но все равно отбросит последнюю строку, если она не заканчивается новой строкой.
  3. "$(...)" удалит столько новых строк, сколько их есть, поэтому я заканчиваю ... символом ; echo -n a и использую echo -n "${line:0:-1}": это удаляет последний символ (который есть a) и сохраняет столько новых строк, сколько было во входных данных (включая отсутствие).
58
ответ дан 24 November 2019 в 02:11
поделиться

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

$ cat template.txt
the number is ${i}
the dog's name is ${name}

$ cat replace.sed
s/${i}/5/
s/${name}/Fido/

$ sed -f replace.sed template.txt > out.txt

$ cat out.txt
the number is 5
the dog's name is Fido
31
ответ дан 24 November 2019 в 02:11
поделиться

Я бы сделал это таким способом, вероятно, менее эффективным, но более легким для чтения / поддержки.

TEMPLATE='/path/to/template.file'
OUTPUT='/path/to/output.file'

while read LINE; do
  echo $LINE |
  sed 's/VARONE/NEWVALA/g' |
  sed 's/VARTWO/NEWVALB/g' |
  sed 's/VARTHR/NEWVALC/g' >> $OUTPUT
done < $TEMPLATE
8
ответ дан 24 November 2019 в 02:11
поделиться
Другие вопросы по тегам:

Похожие вопросы: