У меня есть скелетный текстовый файл со строками-заполнителями:
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>
Если вы действительно знаете, что делаете, и не хотите создавать резервную копию, вам необходимо предоставить пустую строку в OSX для параметра -i: sed -i '' 's/PLACEHOLDER_1/string 1/g;s/PLACEHOLDER_2/string 2/g' <file> ... ссылка: blog.mpdaugherty.com/2010/05/27/…
Не работает, вроде делает второй проход. эхо "AB" | sed 's / A / B / g; s / B / A / g' возвращает AA, а не BA. Также происходит с новой строкой между A и B.
Чего вы ждете? Вы говорите заменить A-> B, но затем снова замените его на B-> A. Вы хотите, чтобы они выполнялись исключительно или как одно выражение?
Основываясь на предыдущем ответе, возможно, использовать массив и вычислить строку 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) -release (i386-apple-darwin9.0)»
Это потому, что вам нужны кавычки вокруг параметров, в которых есть пробелы. Измените «sed -i» на «sed -i '» и после цикла добавьте другую цитату, и тогда все должно работать.
Вы говорите "проверено с помощью bash", но ваш shebang говорит "sh". Связан ли sh с bash в вашей системе? Если да, то разве его поведение не зависит от его названия?
sh - это bash в моей системе, но (как ни странно) он не связан. У меня есть / bin / sh и bin / bash, два разных файла. Полагаю, это причуда Mac. Я не знаю, меняет ли GNU bash свое поведение, если он вызывается как 'sh', а не как 'bash'.
Вот способ сделать это без 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, никаких циклов, только волосатое вложение и кавычки. Я почти уверен, что все цитаты защитят вас от вредоносных файлов в файле шаблона, но я не собираюсь этого гарантировать.
Вы можете использовать -e в любом эхо для интерпретации экранирования обратной косой черты, например \ n, в вашем шаблоне и / или заполнителях.
Неа. Не безопасно. Шаблоны могут включать «$ (команда)», которая может делать плохие вещи. Вы должны знать, можете ли вы доверять своему шаблону. Вы были предупреждены.
Кого волнует, безопасно ли это, если вы не собираетесь отдавать его пользователям? Мне нужно, чтобы он автоматически сгенерировал некоторый html на основе содержимого, которое я полностью контролирую. :) +1!
Кстати, если вам нужно сохранить кавычки в результате, вы можете сначала избежать их с помощью sed: echo "$ (eval" echo \ "$ (sed 's / \" / \\\ "/ g' $ template) \" " ) "> $ outputfile
echo "$(eval "echo \"$template\"")" > $outputfile у меня не работает в сценарии, но работает в командной строке. Почему?
Оказывается, я слишком много пытался сделать в своем файле шаблона. Простая замена переменных работает нормально.
Мое решение только для 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 в конце исходного файла!)
Вы не можете ставить пробелы вокруг знаков равенства.