arturochari
arturochari

Reputation: 31

Bash cannot echo $(hostname) embedded in variable

If I echo a string which contains the $(hostname) command, then it works fine. For example, run in terminal:

echo "http://$(hostname)/main.html"
http://artur/main.html

But if I get that string from a file (previously doing cat to a variable) when I try to print with echo, it does not works:

$ cat site
http://$(hostname)/main.html
$ mysite=$(cat site)
$ echo $mysite
http://$(hostname)/main.html

What am I doing wrong? Any idea?

Upvotes: 3

Views: 7131

Answers (2)

John1024
John1024

Reputation: 113864

The shell performs variable expansion and the shell performs command substitution but it does not do them recursively:

  1. The result of a variable expansion will not be subjected to any further variable expansion or command substitution.

  2. The result of a command substitution will not be subjected to any further variable expansion or command substitution.

This is a good thing because, if it was done recursively, there would be all manor of unexpected results and security issues.

One solution is to use eval. This is a generally dangerous approach and should be regarded as a last resort.

The safe solution is to rethink what you want. In particular, when do you want hostname evaluated? Should it be evaluated before the site file is created? Or, should it be evaluated when the code is finally run? The latter appears to be what you want.

If that is the case, consider this approach. Put %s in the site file where you want the host name to go:

$ cat site
http://%s/main.html

When you read the site file, use printf to substitute in the host name:

$ mysite=$(printf "$(cat site)" "$(hostname)")
$ echo "$mysite"
http://artur/main.html

With bash, an alternative for the form for the above is:

$ printf -v mysite "$(< site)" "$HOSTNAME"
$ echo "$mysite"
http://artur/main.html

Upvotes: 10

anishsane
anishsane

Reputation: 20980

If you only need the placeholder 'hostname' to be replaced by actual hostname, you could use either of these methods:

With your existing site file:

$ cat site
http://$(hostname)/main.html
$ mysite=$(sed 's|\$(hostname)|'"$(hostname)"'|g' site) # or
$ mysite=$(awk '{print gensub("\\$\\(hostname\\)",hostname,"g", $0);}' "hostname=$(hostname)" site)
$ # Note: Above `sed` based method has risk of shell injection. `awk` option is safer.
$ echo "$mysite"
http://artur/main.html

Or if you don't mind changing your site file contents, there is a tool, which is typically used for such purposes - to replace placeholders by actual values: m4 - macro processor

$ cat site
http://HOSTNAME/main.html
$ # HOSTNAME is the placeholder here; can be any identifier string.
$ mysite=$(m4 -D "HOSTNAME=$(hostname)" site)
$ echo "$mysite"
http://artur/main.html

Upvotes: 0

Related Questions