0

Context

I am writting a .sh file which read a .config file. In this .config file (which I can't edit) there are some variables. I want to test if those variables are defined as environment variables.

.config file:

APPLICATION_PATH=/var/www/application
MONGO_DATA_PATH=/var/lib/mongodb
MYSQL_DATA_PATH=/var/lib/mysql

test.sh file:

#!/bin/sh
if test -e ../my_folder/.config                      # Test if the .config file exists
then
    cat ../my_folder/.config | while read line; do   # Read the .config file line per line

        env_var="${line%=*}"                         # Get the part before the '=' character of the current line (e.G. APPLICATION_PATH)
        echo $env_var                                # Display the var (e.G. APPLICATION_PATH)

                                                     # Here, I would like to display the env var,
                                                     # e.G. like it would do using echo $APPLICATION_PATH
                                                     # but using the $env_var

        ( "echo \$$env_var" )                        # Throw an error
    done
fi

Problem

It seems that ( "echo \$$env_var" ) is not possible. When I run test.sh, it displays this:

APPLICATION_PATH

./test.sh: ligne 13: echo $APPLICATION_PATH : not found

MONGO_DATA_PATH

./test.sh: ligne 13: echo $MONGO_DATA_PATH : not found

MYSQL_DATA_PATH

./test.sh: ligne 13: echo $MYSQL_DATA_PATH : not found

Question

How can I test if there is an environment variable using $env_var?

darckcrystale
  • 1,582
  • 2
  • 18
  • 40

2 Answers2

0

You could use the method mentioned here: Is it possible to build variable names from other variables in bash?

So accordingly your code would change to the following:

#!/bin/sh
if test -e ../my_folder/.config                     
then
cat ../my_folder/.config | while read line; do

    env_var="${line%=*}"                         
    echo $env_var                                
    eval "echo \$$env_var"                        # This works
done
fi
jayanth
  • 110
  • 1
  • 9
  • Could you replace the first line with "#!/bin/sh -x " and then run the script to see which line is throwing this error ? – jayanth Jun 07 '17 at 11:39
  • The line throwing the error is `echo ${!env_var}` and it's because i'm not using `/bin/bash` but `/bin/sh`. – darckcrystale Jun 07 '17 at 11:40
  • Hmm is using /bin/bash not an option ? The question did mention the problem was in bash. I assumed your /bin/sh is a symlink to /bin/bash which is the case in my distro. – jayanth Jun 07 '17 at 11:54
  • Sorry, I don't know the name of `sh`, that's why I've written "bash" :( My script could be run on several different distros (we have for example Ubuntu, Fedora, Arch), that's why I don't really want to use `/bin/bash` as I don't know if it's available on all distributions :/ – darckcrystale Jun 07 '17 at 11:58
  • 1
    You can find out what shell you are using by running "echo $SHELL". In case its not bash, I think most shells should support 'eval "echo \$$env_var"'. I modified the answer to this. – jayanth Jun 07 '17 at 12:05
0

If you can sacrifice portability, you should use indirect parameter expansion. The availability and exact syntax varies from shell to shell; this is how you would do it in bash:

while IFS== read -r varname _; do
  printf '%s\n' "${!varname}"
done < ../my_folder/.config

If you want to sacrifice safety, you would do use eval:

while IFS== read -r varname _; do
  eval "printf '%s\n' \$$varname"
done < ../my_folder/.config

Sacrificing simplicity is beyond the scope of Stack Overflow. One possibility, though, is to use expr to ensure that varname only contains a valid shell identifier before using eval.

while IFS== read -r varname _; do
  expr "$varname" : '[[:alpha:]_][[:alnum:]_]*' || continue
  eval "printf '%s\n' \$$varname"
done < ../my_folder/.config
chepner
  • 497,756
  • 71
  • 530
  • 681