3

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?

1
  • 4
    $(cat site) can be replaced with $(< site). Commented Sep 7, 2016 at 6:09

2 Answers 2

10

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
Sign up to request clarification or add additional context in comments.

2 Comments

In Bash, you can (mostly) use the variable HOSTNAME instead of the command hostname: printf -v mysite "$(< site)" "$HOSTNAME".
@gniourf_gniourf Good point. Answer updated to use HOSTNAME for the bash solution.
0

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.