-------------------------------------------------------------------------------
Creating and using Template files.
Templating is used in the configuration of software as it is being installed.
That is one 'source config' is used to define all the places in multiple files
where that value needs to be used. Such as in scripts, configuration files,
for data such as Path, Programs to call, data files, web addresses, etc.
It is also (and more intuitively thought about) for the preperation and mailing
of pre-formatted mail to large numbers of people.
Typically files/strings will have special placeholders, which are specially
labeled strings not typically found in the file, that are replaced with
pre-defined values for that label. These values are pre-defined from a common
higherlevel configuration source (source code templating), or perhaps is
a large array of such values from a database, (mail templating).
Examles if placeholders that may be used.
${label} or $label
<% $label %>
===label===
{{label}}
VAR_label
The substition needs to be done regardless of quoting or other syntax of the
file, as such ideally the placeholder should be unique and not part of the
normal syntax of the file, whatever that may be (program, data, etc).
IT also needs ways to add the 'placeholder' without the substitution.
However there is no ideal solution that is common to all UNIX systems, that
works in all situations.
Here we look at various techniques and methods, I have seen.
===============================================================================
envsubst
This is a GUI tool, and as such is available on almost all UNIX machines.
This looked for $VARIABLE and ${VARIABLE} strings in files and replaces them
with the contents of the environment variables of the same name. If no such
environment variable is found, it is left as is.
Example...
Input...
=======8<--------CUT HERE----------
ServerName ${SERVER_NAME}
ServerAlias ${SERVER_ALIAS}
DocumentRoot "${DOCUMENT_ROOT}"
=======8<--------CUT HERE----------
Command....
=======8<--------CUT HERE----------
export PORT="443"
export SERVER_NAME="example.com"
export SERVER_ALIAS="www.example.com"
export DOCUMENT_ROOT="/var/www/html/"
envsubst < apache.tmpl > my_apache_site.conf
=======8<--------CUT HERE----------
Output...
=======8<--------CUT HERE----------
ServerName example.com
ServerAlias www.example.com
DocumentRoot "/var/www/html/"
=======8<--------CUT HERE----------
Notes, and posible Problems...
* There are a lot of environment variables that are already set
that may also be substituted, but probably should NEVER be substituted!
For example $PATH is common in shell scripts, as it is a envvar!
* The ${..} is used for situations like "${noun}ify" (Bash Syntax)
-------------------------------------------------------------------------------
"sed" templating...
This uses 's|||' commands to avoid conflict with '/'
=======8<--------CUT HERE----------
sed -e 's|===BROWSERDIR===|'"$BROWSERDIR"'|' \
-e 's|===LIBRARY_RC===|'"$LIBRARY_RC"'|' \
-e '/===COLOR_SETTINGS_DIVIDER===/d' \
< file.tmpl >file
=======8<--------CUT HERE----------
NOTE: this method works well in Makefiles!
BUT while the above can handle '/' it will not handle quotes, or other
special 'sed' controls in the substituted values.
A simular technique can be used in perl, with better handling.
-------------------------------------------------------------------------------
Bash (Pure) Templating
=======8<--------CUT HERE----------
#!/bin/bash
while read -r line ; do
while [[ "$line" =~ (.*)(\$\{[a-zA-Z_][a-zA-Z_0-9]*\})(.*) ]] ; do
PRE=${BASH_REMATCH[1]}
POST="${BASH_REMATCH[4]}${line:$end_offset:${#line}}"
LABEL="{BASH_REMATCH[3]}"
eval 'VALUE="$'$VARNAME'"'
line="$PRE$VALUE$POST"
end_offset=${#PRE}
done
echo -n "${line:0:-1}"
done
=======8<--------CUT HERE----------
-------------------------------------------------------------------------------
Perl templating
This uses environment variables to replace {{label}} placeholders.
perl -pe 's/\{\{(\w+)\}\}/(defined $ENV{$1}?$ENV{$1}:"missing var $1")/eg' \
< infile > outfile
OR using a perl hash table of substitutons...
=======8<--------CUT HERE----------
#!/usr/bin/env perl
my %replace = ( 'dbName' => 'testdb', 'somethingElse' => 'fooBar' );
undef $/;
my $buf = ;
$buf =~ s/\$\{$_\}/$replace{$_}/g for keys %replace;
print $buf;
=======8<--------CUT HERE----------
-------------------------------------------------------------------------------
Python Templating Class
This is in many ways simular to "envsubst" above, but using a pythion
dictionary instead of environment variables.
It replaces ${name} or $name with the value of 'name' if present in
the given dictionary.
=======8<--------CUT HERE----------
# A Python program to demonstrate the
# working of the string template
from string import Template
# List Student stores the name and marks of three students
Student = [('Ram',90), ('Ankit',78), ('Bob',92)]
# We are creating a basic structure to print the name and
# marks of the students.
t = Template('Hi $name, you have got $marks marks')
for i in Student:
print (t.substitute(name = i[0], marks = i[1]))
=======8<--------CUT HERE----------
-------------------------------------------------------------------------------
Bash-TPL https://github.com/TekWizely/bash-tpl
(approx 1100 line single script)
Small BASH script to do templating, that also tries to ensure correct
formating (when you add extra indenting for a templated section.
Default the placeholders are: <% $NAME %>
But this can be changed!
Values come from environment, OR from numbered arguments...
bash-tpl test.tpl TekWizely
with "test.tpl"
Hello <% $1 %>
Also includes other directives (like 'INCLUDE')
Ability to run a small scripts to work out the substition.
As a placeholder, line, or even a block within the file.
Hello <%% echo $NAME | tr '[:lower:]' '[:upper:]' %>
Template comments.
or a whole line (startung with '%')
And many other features.
-------------------------------------------------------------------------------
Bash "templater" - https://github.com/vicentebolea/bash-templater
Bash Equivelent (reading from a variable list)...
Basically reads variables into script and a array of the labels used.
Then goes though template file line by line replacing keywords in a loop
templater var_file file
with var_file of the form
NAME=John Doe
EMAIL=john.doe\@mail.server
example template file...
@@@NAME@@@ <@@@EMAIL@@@>
=======8<--------CUT HERE----------
source "$1" # read variables into bash!
mapfile -t keywords < <(sed -n 's/^\([A-Za-z0-9_]\+\)=.*$/\1/p' "$1")
for read line; do
for keyword in "${keywords[@]}"; do
value="$(echo "${!keyword}" | sed 's/\//\\\//g')"
line=`sed "s@\@\@\@${keyword}\@\@\@@${!keyword}@g" <<<"$line"`
done
echo "$line"
done < /dev/stdin
=======8<--------CUT HERE----------
WARNING: it reads variables into the bash script directly!
As such you can NOT use specific varibales like 'keyword' or 'line' or some
bash specific variables, or it will have unexpected results.
-------------------------------------------------------------------------------
Bash "renderest" - https://github.com/relaxdiego/renderest
Looks up the variable names from the template file, and
uses"{{label}}" placeholders in the input template.
This generates "sed" expressions from provided environment variables, giving
a warning if a variable is not found.
In summery...
=======8<--------CUT HERE----------
# Get all variable names used in the template
varnames=$(grep -oE '\{\{([A-Za-z0-9_]+)\}\}' $1 |
sed -rn 's/.*\{\{([A-Za-z0-9_]+)\}\}.*/\1/p' | sort | uniq)
# sed expressions
expressions=""
for varname in $varnames; do
# checks for existance of varname
[ -z ${!varname} ] && echo "ERROR: $varname is empty/not-found" >&2
value="$(echo "${!varname}" | sed 's/\//\\\//g')"
expressions+="-e 's/\{\{$varname\}\}/${value}/g' "
done
eval sed "$expressions" "$1"
=======8<--------CUT HERE----------
NOTE: The 'eval' probbaly should be removed!
-------------------------------------------------------------------------------
Apache Server Side Includes. (SHTML)
Files ending in ".shtml" can be processed by apache to do variable
substituitions and file inclusions, before the resulting HTML is set to calling
web clients. Any expressions embedded in the SHTML, is replaced.
These can include common variable and file substitutions, which is what I used
it for.
I used SHTML a lot in my web pages, and my web site relied on it. I did not
what to re-work that templating system when I switched over to a static page
web server provider.
Specifically I used "Templated Includes", as shown in...
https://antofthy.gitlab.io/info/www/apache_ssi.txt
It was simple and let me desing a 'html' object that I can add to the resulting
HTML files hundreds of times.
Unfortunatally it is only used by the Apache Web Server!
My solution was to have a local only Apache webserver which I then call
to convert ".shtml" pages to ".html" pages before uploading them to the
static web server provider (github).
This also allowed me to generate very fancy directory index pages, where
needed, before uploading to my web provider. Without having to change the way
I did things.
I would LOVE it if a offline SHTML to HTML converter was developed.
-------------------------------------------------------------------------------
Other Templating programs
mo - mustache templates in bash
esh - embedded shell (written in sh)
cookie - https://github.com/bbugyi200/cookie
not a lot of documentation
shtpl - https://github.com/mlorenzo-stratio/shtpl
Bash uses jinja templating syntax (lots of if/loop macro controls)
sigil - https://github.com/gliderlabs/sigil
simple template and macros,
label values can be set from command line
Placeholds can be ${label} (-p option) or {{ $label }}
or even user specified delimiters
written in "Go" and based on "Go" templating package
-------------------------------------------------------------------------------