Заполнение заполнителей в файле за один проход

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

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.

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

Вы не можете ставить пробелы вокруг знаков равенства.

Dennis Williamson 29.05.2009 09:40
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
6
1
10 213
5
Перейти к ответу Данный вопрос помечен как решенный

Ответы 5

Ответ принят как подходящий

Вы по-прежнему можете использовать 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/…

pulkitsinghal 24.02.2013 21:25

Не работает, вроде делает второй проход. эхо "AB" | sed 's / A / B / g; s / B / A / g' возвращает AA, а не BA. Также происходит с новой строкой между A и B.

Ambroz Bizjak 19.06.2014 02:12

Чего вы ждете? Вы говорите заменить A-> B, но затем снова замените его на B-> A. Вы хотите, чтобы они выполнялись исключительно или как одно выражение?

Adam Peck 21.06.2014 00:24

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

Adam Peck 02.01.2009 20:35

Вы говорите "проверено с помощью bash", но ваш shebang говорит "sh". Связан ли sh с bash в вашей системе? Если да, то разве его поведение не зависит от его названия?

Dennis Williamson 29.05.2009 09:46

sh - это bash в моей системе, но (как ни странно) он не связан. У меня есть / bin / sh и bin / bash, два разных файла. Полагаю, это причуда Mac. Я не знаю, меняет ли GNU bash свое поведение, если он вызывается как 'sh', а не как 'bash'.

David Poole 29.05.2009 17:44

Вот способ сделать это без 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, в вашем шаблоне и / или заполнителях.

Dennis Williamson 30.05.2009 00:57

Неа. Не безопасно. Шаблоны могут включать «$ (команда)», которая может делать плохие вещи. Вы должны знать, можете ли вы доверять своему шаблону. Вы были предупреждены.

Dennis Williamson 30.05.2009 03:35

Кого волнует, безопасно ли это, если вы не собираетесь отдавать его пользователям? Мне нужно, чтобы он автоматически сгенерировал некоторый html на основе содержимого, которое я полностью контролирую. :) +1!

Kalle 17.08.2012 00:44

Кстати, если вам нужно сохранить кавычки в результате, вы можете сначала избежать их с помощью sed: echo "$ (eval" echo \ "$ (sed 's / \" / \\\ "/ g' $ template) \" " ) "> $ outputfile

Kalle 17.08.2012 00:45

echo "$(eval "echo \"$template\"")" > $outputfile у меня не работает в сценарии, но работает в командной строке. Почему?

Will Hains 16.08.2013 04:24

Оказывается, я слишком много пытался сделать в своем файле шаблона. Простая замена переменных работает нормально.

Will Hains 16.08.2013 04:39

Мое решение только для 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 в конце исходного файла!)

Другие вопросы по теме