3

I have this code in bash

#!/usr/bin/env bash

DB_NAME=$(CORE_CONFIG=core.config.core_test python -c "from core import config; print config.DATABASE['db_name']")

What I actually want is:

#!/usr/bin/env bash

ENV_VARIABLE="CORE_CONFIG=core.config.core_test"

DB_NAME=$($ENV_VARIABLE python -c "from core import config; print config.DATABASE['db_name']")

However bash complains that CORE_CONFIG is not a command.

I tried I think everything backticks, then nesting in various configurations. It has either no effect or 'command not found'.

How to do it properly?

  • This raises the question, why are you trying to embed an environment in a single variable in the first place? – chepner Dec 16 '15 at 17:18
  • I tried to define extra env variable for this one time sub-command, however depends what script is supposed to do, this env is different, hence it had to become a variable. One can do BOOM=HEADSHOT python -c "...", right? So I figure out it's ok to use $ENV_PREFIX python -c "...", right? – Drachenfels Dec 16 '15 at 17:21
  • Show the context where it needs to be a variable. How does ENV_VARIABLE get set in the first place? Surely it isn't simply hard-coded, or there would be no need for it. – chepner Dec 16 '15 at 17:25
  • Here you go, full script -> sprunge.us/hdgh – Drachenfels Dec 16 '15 at 17:35
4

An assignment is only recognised as such if the = is literal and unquoted, only in words before the first argument, and if the part to the left of the = forms a valid variable name.

In any other case, the word is considered as a command argument, or several if word splitting or globbing generate more (and the first argument is used to derive the command to execute).

Here, you could do:

DB_NAME=$(
  export "$ENV_VARIABLE"
  python...
)

There, the content of the variable is passed as an argument to export, and export treats it as an env var assignment.

Note that $(...) creates a subshell environment, so that variable will only be exported to that python command.

  • This one is the most complex answer so far and one that worked. Thank you. Interestingly newlines in $() are important in your answer. I assume that it's related to globbing you have mentioned. Still I find bash a bit confusing and awkward to me. – Drachenfels Dec 16 '15 at 17:02
1

Or use the env command to set the environment variables.

bash-4.1$ env_foo="xxx=a xxxx=b"
bash-4.1$ env $env_foo perl -E 'say "$_=$ENV{$_}" for grep /^xx/, keys %ENV'
xxx=a
xxxx=b
bash-4.1$ (echo '#!/bin/bash'; history 3 | head -2 | perl -anE 'shift @F; say "@F"') > a_script
bahs-4.1$ 
  • Could you please improve your answer in context of being executed inside of bash script. – Drachenfels Dec 16 '15 at 16:48
  • Sure, added a command to show how to make a script from the given commands. – thrig Dec 16 '15 at 17:10
  • Mate if that supposed to be troll it was very bad one. I gave very specific script to get very specific answer. While I understand env might work in my case it's throwing a lot more errors. Obviously now I can either learn about env and improve your answer so it's workable for me (I am making assumption in here it will actually work, because you tested, right?), or you can put some effort and make your answer meaningful. – Drachenfels Dec 16 '15 at 17:29
1

Your script has this block:

if [ "$1" = "1" ]; then
    ENV_PREFIX=""
elif [ "$1" = "2" ]; then
    ENV_PREFIX="export CORE_CONFIG=core.config.config_api_test"
elif [ "$1" = "3" ]; then
    ENV_PREFIX="export CORE_CONFIG=core.config.config_nosetest"
else
    echo "Unrecognised mode, options are 1 - default environment, 2 - api test, 3 - nosetest)"
    exit 1
fi

Just export the value right away; your shell script doesn't care about it, but will pass it on to Python when it is called.

if [ "$1" = "1" ]; then
    :  # Do nothing
elif [ "$1" = "2" ]; then
    export CORE_CONFIG="core.config.config_api_test"
elif [ "$1" = "3" ]; then
    export CORE_CONFIG="core.config.config_nosetest"
else
    echo "Unrecognised mode, options are 1 - default environment, 2 - api test, 3 - nosetest)"
    exit 1
fi

DB_PORT=5432
DB_USER=$(
    python -c "from core import config; print config.DATABASE['user']"
)
DB_NAME=$(
    python -c "from core import config; print config.DATABASE['db_name']"
)
DB_PASS=$(
    python -c "from core import config; print config.DATABASE['password']"
)
DB_HOST=$(
    python -c "from core import config; print config.DATABASE['host']"
)

unset CORE_CONFIG   # Optional
  • But this variable is already set in my shell, so I will have to save variable into temporary container than recover it at the end of script and what if there is an error in the middle and script is interrupted? – Drachenfels Dec 16 '15 at 17:48
  • Changes in this script do not affect the value in the caller's environment, unless you are sourcing it. – chepner Dec 16 '15 at 17:50
  • Still it overwrites what I currently have, right? Most important thing is that I want to set env variables on per-subcommand basis, while different if's can modify it depends on runtime. – Drachenfels Dec 16 '15 at 17:56
0

From the Bash reference manual:

If the first character of parameter is an exclamation point (!), a level of variable indirection is introduced. Bash uses the value of the variable formed from the rest of parameter as the name of the variable; this variable is then expanded and that value is used in the rest of the substitution, rather than the value of parameter itself. This is known as indirect expansion.

So you can do that:

DB_NAME=$(${!ENV_VARIABLE} python -c "from core import config; print config.DATABASE['db_name']")
  • No, ${!ENV_VARIABLE} expands to the value of the variable named by $ENV_VARIABLE, CORE_CONFIG=core.config.core_test is not a valid variable name, so ${!ENV_VARIABLE} expands to nothing. – Stéphane Chazelas Dec 16 '15 at 16:49

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.