Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 2 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
language: bash
script: ./test.sh
42 changes: 24 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
# BASH Templater
Very simple templating system that replace {{VAR}} by $VAR environment value
Supports default values by writting {{VAR=value}} in the template

Very simple templating system that replace `{{VAR}}` by `$VAR` environment value.

Supports default values by writting `{{VAR=value}}` in the template.

[![Build Status](https://travis-ci.org/lavoiesl/bash-templater.svg?branch=master)](https://travis-ci.org/lavoiesl/bash-templater)

## Author

Expand All @@ -12,36 +16,38 @@ See http://code.haleby.se/2015/11/20/simple-templating-engine-in-bash/ and http

## Installation

To install templater in linux type:
`templater.sh` has no external dependencies. You can use it by directly executing.

To install `templater.sh` globally 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
sudo curl -L https://raw.githubusercontent.com/johanhaleby/bash-templater/master/templater.sh -o /usr/local/bin/templater.sh
sudo chmod +x /usr/local/bin/templater.sh

## Usage

```bash
VAR=value templater template
VAR=value templater.sh template
```

Read variables from file:

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

e.g.:
```bash
# variables.txt
# The author
AUTHOR=Johan
# The version
VERSION=1.2.3
```
# Using external configuration file (and don't print the warnings)
templater.sh template -f variables.txt -s

Don't print any warning messages:
# Passing arguments directly
VAR=value templater.sh template

```bash
templater template -f variables.txt -s
# Evaluate /tmp/foo and pass those variables to the template
# Useful for defining variables in a file
# Parentheses are important for not polluting the current shell
(set -a && . /tmp/foo && templater.sh template)

# A variant that does NOT pass current env variables to the templater
sh -c "set -a && . /tmp/foo && templater.sh template"
```

## Examples
Expand Down
24 changes: 9 additions & 15 deletions examples/vhost-php.conf
Original file line number Diff line number Diff line change
@@ -1,28 +1,22 @@
{{LOG_DIR=/var/log/apache2}}
{{RUN_DIR=/var/run/php-fpm}}
{{FCGI=$RUN_DIR/$DOMAIN.fcgi}}
{{SOCKET=$RUN_DIR/$DOMAIN.sock}}
{{EMAIL=$USER@$DOMAIN}}
{{DOC_ROOT=/home/$USER/sites/$DOMAIN/htdocs}}
<VirtualHost *:80>
ServerAdmin {{EMAIL}}
ServerName {{DOMAIN}}
ServerAlias www.{{DOMAIN}}
ServerAdmin nobody@example.com
ServerName example.com
ServerAlias www.example.com

DocumentRoot "{{DOC_ROOT}}"
DocumentRoot "/home/nobody/sites/example.com/htdocs"

<Directory "{{DOC_ROOT}}">
<Directory "/home/nobody/sites/example.com/htdocs">
AllowOverride All
Order allow,deny
Allow From All
</Directory>

AddHandler php-script .php
Action php-script /php5.fastcgi virtual
Alias /php5.fastcgi {{FCGI}}
FastCGIExternalServer {{FCGI}} -socket {{SOCKET}}
Alias /php5.fastcgi /var/run/php-fpm/example.com.fcgi
FastCGIExternalServer /var/run/php-fpm/example.com.fcgi -socket /var/run/php-fpm/example.com.sock

LogLevel warn
CustomLog {{LOG_DIR}}/{{DOMAIN}}.access.log combined
ErrorLog {{LOG_DIR}}/{{DOMAIN}}.error.log
CustomLog /var/log/apache2/example.com.access.log combined
ErrorLog /var/log/apache2/example.com.error.log
</VirtualHost>
28 changes: 28 additions & 0 deletions examples/vhost-php.tpl.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{{LOG_DIR=/var/log/apache2}}
{{RUN_DIR=/var/run/php-fpm}}
{{FCGI=$RUN_DIR/$DOMAIN.fcgi}}
{{SOCKET=$RUN_DIR/$DOMAIN.sock}}
{{EMAIL=$USER@$DOMAIN}}
{{DOC_ROOT=/home/$USER/sites/$DOMAIN/htdocs}}
<VirtualHost *:80>
ServerAdmin {{EMAIL}}
ServerName {{DOMAIN}}
ServerAlias www.{{ DOMAIN }}

DocumentRoot "{{DOC_ROOT}}"

<Directory "{{ DOC_ROOT }}">
AllowOverride All
Order allow,deny
Allow From All
</Directory>

AddHandler php-script .php
Action php-script /php5.fastcgi virtual
Alias /php5.fastcgi {{FCGI}}
FastCGIExternalServer {{ FCGI }} -socket {{SOCKET}}

LogLevel warn
CustomLog {{LOG_DIR}}/{{DOMAIN}}.access.log combined
ErrorLog {{LOG_DIR }}/{{ DOMAIN}}.error.log
</VirtualHost>
119 changes: 83 additions & 36 deletions templater.sh
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ readonly PROGNAME=$(basename $0)
config_file="<none>"
print_only="false"
silent="false"
nounset="false"
verbose="false"

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

Expand All @@ -46,6 +48,10 @@ where:
Specify a file to read variables from
-s, --silent
Don't print warning messages (for example if no variables are found)
-u, --nounset
Unset variables throws error instead of a warning
-v, --verbose
Verbose output

examples:
VAR1=Something VAR2=1.2.3 ${PROGNAME} test.txt
Expand All @@ -57,13 +63,6 @@ if [ $# -eq 0 ]; then
exit 1
fi

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

template="${1}"

if [ "$#" -ne 0 ]; then
while [ "$#" -gt 0 ]
Expand All @@ -76,32 +75,47 @@ if [ "$#" -ne 0 ]; then
-p|--print)
print_only="true"
;;
-f|--file)
config_file="$2"
-f|--file) shift
config_file="$1"
;;
-s|--silent)
silent="true"
;;
--)
break
-u|--nounset)
nounset="true"
;;
-v|--verbose)
verbose="true"
;;
-*)
echo "Invalid option '$1'. Use --help to see the valid options" >&2
exit 1
;;
# an option argument, continue
*) ;;
# an option argument, this must be the template
*)
template="$1"
;;
esac
shift
done
fi

vars=$(grep -oE '\{\{[A-Za-z0-9_]+\}\}' "${template}" | sort | uniq | sed -e 's/^{{//' -e 's/}}$//')
if [[ ! -f "$template" ]]; then
echo "You need to specify a template file" >&2
echo "$usage"
exit 1
fi



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

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

# Load variables from file if needed
Expand All @@ -111,42 +125,72 @@ if [ "${config_file}" != "<none>" ]; then
echo "$usage"
exit 1
fi

_pwd=$PWD
cd "$(dirname "$config_file")"
source "${config_file}"
cd "$_pwd"
fi

var_value() {
eval echo \$$1
var="${1}"
eval echo \$"${var}"
}

##
# Escape custom characters in a string
# Example: escape "ab'\c" '\' "'" ===> ab\'\\c
#
function escape_chars() {
local content="${1}"
shift

for char in "$@"; do
content="${content//${char}/\\${char}}"
done

echo "${content}"
}

function echo_var() {
local var="${1}"
local content="${2}"
local escaped="$(escape_chars "${content}" "\\" '"')"

echo "${var}=\"${escaped}\""
}

replaces=""
declare -a replaces
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/}}$//')

#????defaults=$(grep -oE '^\{\{[A-Za-z0-9_]+=.+\}\}$' "${template}" | sed -e 's/^{{//' -e 's/}}$//')
IFS=$'\n'
for default in $defaults; do
var=$(echo "$default" | grep -oE "^[A-Za-z0-9_]+")
current=`var_value $var`
var=$(echo "${default}" | grep -oE "^[A-Za-z0-9_]+")
current="$(var_value "${var}")"

# Replace only if var is not set
if [[ -z "$current" ]]; then
eval $default
if [[ -n "$current" ]]; then
eval "$(echo_var "${var}" "${current}")"
else
eval "${default}"
fi

# remove define line
replaces="-e '/^{{$var=/d' $replaces"
vars="$vars
$current"
replaces+=("-e")
replaces+=("/^{{${var}=/d")
vars="${vars} ${var}"
done

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

if [[ "$print_only" == "true" ]]; then
for var in $vars; do
value=`var_value $var`
echo "$var = $value"
value="$(var_value "${var}")"
echo_var "${var}" "${value}"
done
exit 0
fi
Expand All @@ -155,15 +199,18 @@ fi
for var in $vars; do
value=$(var_value $var | sed -e "s;\&;\\\&;g" -e "s;\ ;\\\ ;g") # '&' and <space> is escaped
if [[ -z "$value" ]]; then
if [ $silent == "false" ]; then
echo "Warning: $var is not defined and no default is set, replacing by empty" >&2
if [[ $nounset == "false" ]]; then
[ $silent == "true" ] || echo "Warning: $var is not defined and no default is set, replacing by empty" >&2
else
echo "ERROR: $var is not defined and no default is set." >&2
exit 1
fi
fi

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

escaped_template_path=$(echo $template | sed 's/ /\\ /g')
eval sed $replaces "$escaped_template_path"
sed "${replaces[@]}" "${template}"
8 changes: 8 additions & 0 deletions test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#!/bin/bash

if diff -u <(USER=nobody DOMAIN=example.com ./templater.sh examples/vhost-php.tpl.conf) examples/vhost-php.conf; then
echo OK
else
echo Differences found
exit 1
fi