3

I need to extract a path that is set within a config file, to use it in a bash script. This is how that path looks like inside said file:

DIR = "${HOME}/test/tmp"

I need to extract it without quotation marks, and this is how i do it:

TESTVAR="$(cat /home/user/path/to/file.conf | grep ^DIR | grep -o '".*"' | tr -d '"')"

The problem is that commands don't interpret ${HOME} variable "properly". Let's say i call echo $TESTVAR - as a result, instead of this:

/home/user/test/tmp

i get that:

${HOME}/test/tmp

so i can't use it as a parameter of commands inside a script!

Pretty please?

3
  • 2
    That's because variable expansion is not called on the results of variable expansion. See man bash.
    – choroba
    Mar 19, 2021 at 12:49
  • 1
    @choroba Thank you. I used 'eval' and it works like a charm
    – wf_
    Mar 19, 2021 at 12:55
  • 1
    Just make sure you get the quoting right if you eval user supplied content. What if they set HOME='blah; rm -rf /;'.
    – choroba
    Mar 19, 2021 at 13:02

2 Answers 2

10

Expansions don't get recursively applied. Doing that would make it impossible to handle arbitrary data with dollar signs embedded. (A related matter is that quotes and redirection and other operators are also just regular characters after expansions.)

A somewhat usual custom is to have config files like that as actual shell script, so (like the ones in Debian's /etc/default), so the file would be

DIR="${HOME}/test/tmp"

and you'd read it with

. configfile

though of course that has the problem that the file is a full shell script, must conform to the shell syntax and the config can run arbitrary commands.

Another possibility would be to run the file through envsubst, e.g. with the file in your question, envsubst < configfile would output:

DIR = "/home/me/test/tmp"

or you could use envsubst '$HOME $OTHER $VARS' to expand just some particular ones.

Note that unlike a shell script would do, envsubst doesn't read any assignments from the input file. E.g. the value of ROOTPATH used on the second line is the one envsubst gets from the environment, it has nothing to do with the "assignment" on the first line:

ROOTPATH=/something/$USER
LOGPATH=$ROOTPATH/logs
1
  • 1
    This is the answer - my thanks and appreciation. I opted out of using eval and replaced 'cat /home/user/path/to/file.conf' with 'envsubst < /home/user/path/to/file.conf'.
    – wf_
    Mar 19, 2021 at 14:03
3

That is a needlessly complicated way of getting what you're after! All you need is (I also changed to lower case variable names, please avoid using CAPS for shell script variables since those are used for environment variables and this can lead to name collisions) :

testvar="$(grep -oP '^DIR\s*=\s*"\K[^"]+' /home/user/path/to/file.conf)"

This would get you testvar=${HOME}/test/tmp. To expand $HOME, you would now need to evaluate it:

testvar=$(eval echo "$testvar")

However, using eval for arbitrary code is very dangerous. If the file you are reading contains a command, that command will be run. So the approaches given in @ilkkachu's answer are much better and safer.

1
  • Well noted with thanks!
    – wf_
    Mar 19, 2021 at 13:57

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .