diff --git a/README.md b/README.md index a62b3ec..70ba73d 100644 --- a/README.md +++ b/README.md @@ -10,11 +10,34 @@ Supports default values by writting `{{VAR=value}}` in the template. Sébastien Lavoie -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 + +`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.sh + sudo chmod +x /usr/local/bin/templater.sh ## Usage + +VAR=value templater.sh template +``` + +Read variables from file: + +```bash +templater.sh template -f variables.txt +``` + +```bash +# Using external configuration file (and don't print the warnings) +templater.sh template -f variables.txt -s -```sh # Passing arguments directly VAR=value templater.sh template diff --git a/templater.sh b/templater.sh index b6fe194..af11b00 100755 --- a/templater.sh +++ b/templater.sh @@ -1,19 +1,136 @@ #!/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="" +print_only="false" +silent="false" +nounset="false" +verbose="false" + +usage="${PROGNAME} [-h] [-d] [-f] [-s] -- + +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) + -u, --nounset + Unset variables throws error instead of a warning + -v, --verbose + Verbose output + +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 [ "$#" -ne 0 ]; then + while [ "$#" -gt 0 ] + do + case "$1" in + -h|--help) + echo "$usage" + exit 0 + ;; + -p|--print) + print_only="true" + ;; + -f|--file) shift + config_file="$1" + ;; + -s|--silent) + silent="true" + ;; + -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, this must be the template + *) + template="$1" + ;; + esac + shift + done +fi + +if [[ ! -f "$template" ]]; 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/}}$//') if [[ -z "$vars" ]]; 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 +if [ "${config_file}" != "" ]; then + if [[ ! -f "${config_file}" ]]; then + echo "The file ${config_file} does not exists" >&2 + echo "$usage" + exit 1 + fi + _pwd=$PWD + cd "$(dirname "$config_file")" + source "${config_file}" + cd "$_pwd" +fi + var_value() { var="${1}" eval echo \$"${var}" @@ -48,7 +165,8 @@ 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/}}$//') +#????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_]+") @@ -69,7 +187,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}" @@ -79,9 +197,14 @@ 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 is escaped if [[ -z "$value" ]]; 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