ninjagecko
ninjagecko

Reputation: 91149

Shell scripting: export test1="a b c" works, but $(echo 'export test2="a b c"') doesn't

I seem to be having issues with some shell scripting (ZSH in particular), where the shell fails to understand exports with spaces in them. The problem only happens when `runcommand` or $(runcommand) is used.

Test case:

# Works fine:
export test1="a b c"

# Does not work:
$(echo 'export test2="a b c"')

The error is something along the lines of export:4: not valid in this context: c". Adding 1-2 \-escapes before the spaces and/or the quotes might change the error message to export:4: not valid in this context: b\.

Might anyone have insight into what the problem is? Thank you.

(The reason I am doing this is a hack to allow python to set shell variables by dynamically generating code which gets run in .myshellrc; if anyone knows of a more elegant way to do this, that would be quite welcome as a comment. Thank you.) edit: To clarify, I am looking for a way to make the above work, or an alternative way to allow an external script to dictate what to export.

(*sigh*, I hope this isn't a version-specific issue in 4.3.12... I think this may have worked in the past.)

Upvotes: 1

Views: 999

Answers (3)

Shawn Chin
Shawn Chin

Reputation: 86974

The issue here is that work splitting is done to the output before it is run as a command. What you end up with is export being called with 3 arguments - test1="a, b, and c".

Using eval as other answers have mentioned is one way to get around it.

An altenative solution would be to use process substitution. This is especially useful if your script is generating multiple lines of code.

Example:

zsh% source =(echo export test1=\"a b c\")
zsh% echo $test1                          
a b c

p.s. You might want to use the <(...) syntax instead of =(...) which will allow it to also work in bash.

Upvotes: 3

user507077
user507077

Reputation:

The usual way to do this is to use eval as kev has said and pass it the full output of the program in question. The program should then produce valid shell code itself:

eval "$(your_script.py)"

And your_script.py would print something like export var1="a b c" (yes, using parenthesis in the output is OK).

An example of a program using this technique is rbenv. The user has to put eval "$(rbenv init -)" in his shell init file, and rbenv init actually outputs quite a lot of code:

export PATH="/opt/rbenv/shims:${PATH}"
source "/opt/rbenv/libexec/../completions/rbenv.zsh"
rbenv rehash 2>/dev/null
rbenv() {
  local command="$1"
  if [ "$#" -gt 0 ]; then
    shift
  fi

  case "$command" in
  shell)
    eval `rbenv "sh-$command" "$@"`;;
  *)
    command rbenv "$command" "$@";;
  esac
}

Upvotes: 2

kev
kev

Reputation: 161964

Take a look at this. You can try:

eval 'export test2="a b c"'

Upvotes: 2

Related Questions