torbatamas
torbatamas

Reputation: 1296

Shell parse string

I read a string from a file with shell script variables, and want to substitute the variables with values in a function like

hello.txt:
-------------
Hello $NAME


a.sh 
-------------
function printout
{
  echo ???somehow_parse??? $1
}

NAME=Joe
printout "$(cat hello.txt)"
NAME=Nelly
printout "$(cat hello.txt)"

The example is not the best, but it describes my problem. In other words: can I use shell as a template engine?

I am using ksh.

Upvotes: 3

Views: 1209

Answers (4)

john_science
john_science

Reputation: 6551

I think the easiest solution is to use the basename utility.

For instance, if you have the following string: a='/home/you/stuff/myfile.txt' you could use commands like:

dirname $a
basename $a
basename $a .txt

and get output that looks like this:

/home/you/stuff
myfile.txt
myfile

Upvotes: 0

Shawn Chin
Shawn Chin

Reputation: 86924

In general, I would go for a search-and-replace approach using sed/awk such as that shown in Kent's answer or this answer.

If you want a shell-only approach, then the standard way would be to use eval. However, this poses a security risk. For example:

[me@home]$ cat hello.txt
hello $NAME; uname -a
[me@home]$ NAME="shawn"
[me@home]$ eval echo "`cat hello.txt`"   # DO NOT DO THIS!
hello shawn
Linux SOMEHOST 2.6.9-101.ELsmp #1 SMP Fri May 27 18:57:30 EDT 2011 i686 i686 i386 GNU/Linux

Notice how a command can be injected into the template!

You can however reduce the risk using this approach:

[me@home]$ eval "OUT=\"`cat hello.txt`\""
[me@home]$ echo $OUT
hello shawn; uname -a

Do note that this is still not foolproof as commands can still be injected using $(cmd) or `cmd`.

In short, you should use eval only if you understand the risks and can control/limit access to the template files.

Here's an example of how this can be applied in your script:

function printout {
    FILENAME=$1
    eval "OUT=\"`cat $FILENAME`\""
    echo $OUT
}

NAME=Joe
printout hello.txt
NAME=Nelly
printout hello.txt

Upvotes: 1

jcollado
jcollado

Reputation: 40414

If you're sure that the contents of your template file is completely safe, that is, it doesn't contain a string to execute a command that might harm your computer, then you can use eval:

#!/bin/bash
NAME=Joe
TEMPLATE=$(cat hello.txt)
eval "echo $TEMPLATE"
NAME=Nelly
eval "echo $TEMPLATE"

Example output:

HELLO Joe
HELLO Nelly

Upvotes: 1

Kent
Kent

Reputation: 195169

like this?

kent$  head hello.txt t.sh
==> hello.txt <==
hello $name

==> t.sh <==
#!/bin/bash

function printout
{
  echo $1|awk -v name="$name" 'gsub(/\$name/,name)'
}
name=xxx
printout "$(cat hello.txt)"
name=yyy
printout "$(cat hello.txt)"

run it:

kent$  ./t.sh
hello xxx
hello yyy

Upvotes: 0

Related Questions