Заполнение заполнителей в файле за один проход
Вопрос
У меня есть текстовый файл скелета со строками-заполнителями:
blah blah blah
blah $PLACEHOLDER_1$
blah
$PLACEHOLDER_2$
и так далее.Конкретная «форма» заполнителей не имеет значения — я могу изменить их на любые, наиболее удобные для конкретной реализации.
У меня есть сценарий bash, в котором я знаю значения заполнителей, и мне нужно создать новый файл, в котором заполнители будут заменены значениями.
#! /bin/sh
PLACEHOLDER_1 = 'string 1'
PLACEHOLDER_2 = 'multiline
string
2'
# TODO: Generate file output.txt from file output.template
# using placeholders above.
Я могу сделать это за несколько проходов с помощью sed, но это неинтересно.Я делаю нет хочу использовать Perl.Я хочу использовать только textutils и bash.
Как лучше всего сделать то, что я хочу, за один проход?
Решение
Вы по-прежнему можете использовать sed для замены за один проход.Вам просто нужно указать все замены в одной команде.
например.
sed -i 's/PLACEHOLDER_1/string 1/g;s/PLACEHOLDER_2/string 2/g' <file>
Другие советы
Вот способ сделать это без sed:
Во-первых, слегка измененный файл шаблона, в котором заполнителями являются переменные bash:
blah blah blah
blah $PLACEHOLDER_1
blah
$PLACEHOLDER_2
И сценарий:
#! /bin/sh
templatefile=output.template
outputfile=output.txt
PLACEHOLDER_1='string 1'
PLACEHOLDER_2='multiline
string
2'
# DONE: Generate file output.txt from file output.template
# using placeholders above.
echo "$(eval "echo \"$(cat $templatefile)\"")" > $outputfile
Вот версия, демонстрирующая шаблон, содержащийся в скрипте, но с некоторыми изменениями.Он также демонстрирует значения по умолчанию, которые также можно использовать в версии файла шаблона, а также в шаблоне можно выполнять математические операции:
#! /bin/sh
template='blah blah blah
blah $PLACEHOLDER_1
blah
${PLACEHOLDER_2:-"some text"} blah ${PLACEHOLDER_3:-"some
lines
of
text"} and the total is: $((${VAL_1:-0} + ${VAL_2:-0}))'
# default operands to zero (or 1) to prevent errors due to unset variables
outputfile=output.txt
# gears spin, bells ding, values for placeholders are computed
PLACEHOLDER_1='string 1'
PLACEHOLDER_2='multiline
string
2'
VAL_1=2
VAL_2=4
unset PLACEHOLDER_3 # so we can trigger one of the defaults
# Generate file output.txt from variable $template
# using placeholders above.
echo "$(eval "echo \"$template\"")" > $outputfile
Никаких sed, никаких циклов, только запутанное вложение и кавычки.Я почти уверен, что цитирование защитит вас от вредоносного содержимого в файле шаблона, но я не собираюсь этого гарантировать.
Основываясь на предыдущем ответе, возможно, использовать массив и вычислить строку sed?
#!/bin/sh
PLACEHOLDER[0]='string 1'
PLACEHOLDER[1]='multiline
string
2'
s="sed -i "
for(( i=0 ; i<${#PLACEHOLDER[*]} ; i++ )) ; do
echo ${PLACEHOLDER[$i]}
s=$s"s/PLACEHOLDER_$i/${PLACEHOLDER[$i]}/g;"
done
echo $s
Однако, похоже, не работает с многострочными строками.
Я не знаю, насколько портативными могут быть массивы Bash.Приведенный выше фрагмент протестирован с использованием «GNU bash, версия 3.2.17(1)-релиз (i386-apple-darwin9.0)»
Мое единственное решение bash:
TEMPLATE='
foo
$var1
bar
$var2'
eval "echo \"$TEMPLATE\""
Я просто наткнулся на этот вопрос, потому что искал то же самое, и нашел envsubst(1)
.
Вы можете использовать envsubst если вы не против использовать переменные среды:
PLACEHOLDER_1='string 1' PLACEHOLDER_2='multiline
string
2' envsubst < output.template
Если у вас много переменных, вы можете сохранить их в файле и просто source
это (не забудьте использовать export
в конце исходного файла!)