Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Fill placeholders in file in single pass

I have a skeleton text file with placeholder strings:

blah blah blah
blah $PLACEHOLDER_1$
blah
$PLACEHOLDER_2$

and so on. Specific "form" of placeholders does not matter -- I may change them to whatever most comfortable for specific implementation.

I have a bash script where I know values for placeholders, and I need to generate a new file, with placeholders replaced with values.

#! /bin/sh
PLACEHOLDER_1 = 'string 1'
PLACEHOLDER_2 = 'multiline 
string 
2'
# TODO: Generate file output.txt from file output.template 
#       using placeholders above.

I may do this in multiple passes with sed, but it is not fun. I do not want to use Perl. I want to use textutils and bash itself only.

What is the best way to do what I want in a single pass?

like image 294
Alexander Gladysh Avatar asked Jan 02 '09 16:01

Alexander Gladysh


2 Answers

Here's a way to do it without sed:

First, a slightly modified template file in which the placeholders are bash variables:

blah blah blah
blah $PLACEHOLDER_1
blah
$PLACEHOLDER_2

And the script:

#! /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

Here's a version that demonstrates a template contained within the script, but with a twist. It also demonstrates default values, which can also be used in the template file version, plus you can do math in the template:

#! /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

No sed, no loops, just hairy nesting and quotes. I'm pretty sure all the quoting will protect you from malicious stuff in a template file, but I'm not going to guarantee it.

like image 153
Dennis Williamson Avatar answered Sep 18 '22 17:09

Dennis Williamson


You can still use sed to do the replace in a single pass. You just need to specify all the replacements in one command.

eg.

sed -i 's/PLACEHOLDER_1/string 1/g;s/PLACEHOLDER_2/string 2/g' <file>
like image 36
Adam Peck Avatar answered Sep 19 '22 17:09

Adam Peck