Loading Variables into a Template with Bash
Here's a simple and efficient method of loading variables into a webpage template with a Bash CGI script.
I've been rewriting a website using Bash scripting, and, for ease of design and maintainance, I wanted to have a page template separate from the actual scripts.
To make it work, my thinking was I had to read the template and then substitute values for variables in the template. I got it working initially with Bash string substitutions, like this:
TEMPLATE=`cat template.txt` TEMPLATE=$((TEMPLATE//#TITLE#/$TITLE))
(In template.txt there's a placeholder #TITLE# for the $TITLE variable.)
But then I ran into a problem. With each variable I added, the Bash script got slower. The complete script, with all variables in place, was taking almost 2 seconds to run! Needless to say that wasn't acceptable performance for a public web script.
So I set out to find a more efficient manner of using templates in Bash. Googling turned up lots of resources like this page that offers solutions using eval, sed and even perl. I tried all these approaches (and more) without satisfactory results. Performance was still very poor.
I put the problem away for a few days and then came back to it, determined to start from scratch. With all thoughts of eval, sed, awk, perl, etc. banished, the solution turned out to be rediculously simple.
#!/bin/bash TITLE="Hello World" TODAY=`date +'%A, %B %d, %Y'` echo "Content-type: text/html" echo "" source template.txt
The template file (template.txt) looks like this:
echo "
<html>
<head>
<title>${TITLE}</title>
</head>
<body>
<h1>${TITLE}</h1>
<p>Today is ${TODAY}</p>
</body>
</html>
"
Simple, clean and fast. Just remember than any double quotes in the template must be escaped with a backslash. For simplicity I just use single quotes for HTML attributes and inline CSS.
Performance of my web script is now blazing-fast -- it runs in about 0.014 second, compared to the previous two seconds :)
render () {
eval "echo \"$(cat $1 | tr \" \')\""
}
render header.html
render body.html
render footer.html
The function is somewhat uglier than just using the "source" builtin but it allows you to remove the "echo" commands from your templates. It also pipes the template through tr to automatically convert all double quotes to single quotes.
echo this is what I want to %REPLACE% right here. |sed 's/%REPLACE%/kick/g'
Yeah that's fine for replacing a few variables but it becomes hard to read and maintain if you use it for large HTML templates. Or more specifically, it's not a template system...it's just sed.