Заполнить заполнители в файле за один проход - PullRequest
6 голосов
/ 02 января 2009

У меня есть скелетный текстовый файл со строками-заполнителями:

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.

Какой лучший способ сделать то, что я хочу, за один проход?

Ответы [ 5 ]

10 голосов
/ 29 мая 2009

Вот способ сделать это без 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

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

9 голосов
/ 02 января 2009

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

например.

sed -i 's/PLACEHOLDER_1/string 1/g;s/PLACEHOLDER_2/string 2/g' <file>
5 голосов
/ 02 января 2009

Основываясь на предыдущем ответе, возможно, использовать массив и вычислить строку 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)»

2 голосов
/ 26 октября 2010

Решение для моего bash:

TEMPLATE='
foo
$var1
bar
$var2'
eval "echo \"$TEMPLATE\""
1 голос
/ 31 марта 2015

Я просто наткнулся на этот вопрос, потому что я искал точно то же самое, и я нашел envsubst(1).

Вы можете использовать envsubst , если не возражаете против использования переменных окружения:

PLACEHOLDER_1='string 1' PLACEHOLDER_2='multiline 
string 
2' envsubst < output.template 

Если у вас много переменных, вы можете сохранить их в файле и просто source его (не забудьте использовать export в конце файла с источником!)

...