Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 35 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,37 @@ Supports default values by writting `{{VAR=value}}` in the template.

Sébastien Lavoie <github@lavoie.sl>

See http://blog.lavoie.sl/2012/11/simple-templating-system-using-bash.html for other details
Johan Haleby

See http://code.haleby.se/2015/11/20/simple-templating-engine-in-bash/ and http://blog.lavoie.sl/2012/11/simple-templating-system-using-bash.html for more details

## Installation

To install templater in linux type:

sudo curl -L https://raw.githubusercontent.com/johanhaleby/bash-templater/master/templater.sh -o /usr/local/bin/templater
sudo chmod +x /usr/local/bin/templater

## Usage

```bash
VAR=value templater template
```

Read variables from file:

```bash
templater template -f variables.txt
```

e.g.:
```bash
# variables.txt
# The author
AUTHOR=Johan
# The version
VERSION=1.2.3
```

```sh
# Passing arguments directly
Expand All @@ -23,6 +51,12 @@ VAR=value templater.sh template
# Parentheses are important for not polluting the current shell
(set -a && . /tmp/foo && templater.sh template)

# Passing variables to template via a file
templater.sh template -f variables.txt

# Squelching all warning messages
templater.sh template -s

# A variant that does NOT pass current env variables to the templater
sh -c "set -a && . /tmp/foo && templater.sh template"
```
Expand Down
145 changes: 130 additions & 15 deletions templater.sh
Original file line number Diff line number Diff line change
@@ -1,19 +1,133 @@
#!/bin/bash
#
# Very simple templating system that replaces {{VAR}} by the value of $VAR.
# Supports default values by writting {{VAR=value}} in the template.
#
# Copyright (c) 2017 Sébastien Lavoie
# Copyright (c) 2017 Johan Haleby
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
#
# See: https://github.com/johanhaleby/bash-templater
# Version: https://github.com/johanhaleby/bash-templater/commit/5ac655d554238ac70b08ee4361d699ea9954c941

# Replaces all {{VAR}} by the $VAR value in a template file and outputs it
# Use with -h to output all variables

if [[ ! -f "$1" ]]; then
echo "Usage: VAR=value $0 template" >&2
readonly PROGNAME=$(basename $0)

config_file="<none>"
print_only="false"
silent="false"

usage="${PROGNAME} [-h] [-d] [-f] [-s] [-o] --

where:
-h, --help
Show this help text
-p, --print
Don't do anything, just print the result of the variable expansion(s)
-f, --file
Specify a file to read variables from
-s, --silent
Don't print warning messages (for example if no variables are found)
-o, --vars-optional
Allow for no variables to be present (simply returns the template as is)

examples:
VAR1=Something VAR2=1.2.3 ${PROGNAME} test.txt
${PROGNAME} test.txt -f my-variables.txt
${PROGNAME} test.txt -f my-variables.txt > new-test.txt"

if [ $# -eq 0 ]; then
echo "$usage"
exit 1
fi

if [[ ! -f "${1}" ]]; then
echo "You need to specify a template file" >&2
echo "$usage"
exit 1
fi

template="$1"
vars=$(grep -oE '\{\{\s*[A-Za-z0-9_]+\s*\}\}' "$template" | sort | uniq | sed -e 's/^{{//' -e 's/}}$//')
template="${1}"

if [ "$#" -ne 0 ]; then
while [ "$#" -gt 0 ]
do
case "$1" in
-h|--help)
echo "$usage"
exit 0
;;
-p|--print)
print_only="true"
;;
-f|--file)
config_file="$2"
;;
-s|--silent)
silent="true"
;;
-o|--vars-optional)
vars_optional="true"
;;
--)
break
;;
-*)
echo "Invalid option '$1'. Use --help to see the valid options" >&2
exit 1
;;
# an option argument, continue
*) ;;
esac
shift
done
fi

vars=$(grep -oE '\{\{[A-Za-z0-9_]+\}\}' "${template}" | sort | uniq | sed -e 's/^{{//' -e 's/}}$//')

if [[ -z "$vars" ]]; then
echo "Warning: No variable was found in $template, syntax is {{VAR}}" >&2
if [ "$vars_optional" == "true" ]; then
if [ "$print_only" == "false" ]; then
cat $template
fi
exit 0
else
if [ "$silent" == "false" ]; then
echo "Warning: No variable was found in ${template}, syntax is {{VAR}}" >&2
fi
exit 1
fi
fi

# Load variables from file if needed
if [ "${config_file}" != "<none>" ]; then
if [[ ! -f "${config_file}" ]]; then
echo "The file ${config_file} does not exists" >&2
echo "$usage"
exit 1
fi

source "${config_file}"
fi

var_value() {
var="${1}"
eval echo \$"${var}"
Expand Down Expand Up @@ -48,8 +162,7 @@ replaces=()
# Reads default values defined as {{VAR=value}} and delete those lines
# There are evaluated, so you can do {{PATH=$HOME}} or {{PATH=`pwd`}}
# You can even reference variables defined in the template before
defaults=$(grep -oE '^\{\{[A-Za-z0-9_]+=.+\}\}$' "${template}" | sed -e 's/^{{//' -e 's/}}$//')
IFS=$'\n'
defaults=$(grep -oE '^\{\{[A-Za-z0-9_]+=.+\}\}' "${template}" | sed -e 's/^{{//' -e 's/}}$//')
for default in $defaults; do
var=$(echo "${default}" | grep -oE "^[A-Za-z0-9_]+")
current="$(var_value "${var}")"
Expand All @@ -69,7 +182,7 @@ done

vars="$(echo "${vars}" | tr " " "\n" | sort | uniq)"

if [[ "$2" = "-h" ]]; then
if [[ "$print_only" == "true" ]]; then
for var in $vars; do
value="$(var_value "${var}")"
echo_var "${var}" "${value}"
Expand All @@ -79,15 +192,17 @@ fi

# Replace all {{VAR}} by $VAR value
for var in $vars; do
value="$(var_value "${var}")"
value=$(var_value $var | sed -e "s;\&;\\\&;g" -e "s;\ ;\\\ ;g") # '&' and <space> is escaped
if [[ -z "$value" ]]; then
echo "Warning: $var is not defined and no default is set, replacing by empty" >&2
if [ $silent == "false" ]; then
echo "Warning: $var is not defined and no default is set, replacing by empty" >&2
fi
fi

# Escape slashes
value="$(escape_chars "${value}" "\\" '/' ' ')";
replaces+=("-e")
replaces+=("s/{{\s*${var}\s*}}/${value}/g")
value=$(echo "$value" | sed 's/\//\\\//g');
replaces="-e 's/{{$var}}/${value}/g' $replaces"
done

sed "${replaces[@]}" "${template}"
escaped_template_path=$(echo $template | sed 's/ /\\ /g')
eval sed $replaces "$escaped_template_path"