The answer to the question you asked is: use eval
.
eval "export test=$(echo "hello world")"
Do take care that the argument to eval
is executed as a piece of shell code. It's usually tricky to get right. For example, the code above sets test
to the 5-character string hello
, not to the 11-character string hello world
. This mimics your original example with zsh -c "export test=$(echo "hello world")"
, which also sets test
to hello
. The reason is that in both cases, the outer shell runs the code and determines that it's calling a command with the argument export test=hello world
. In one case the command is the external program zsh
with a first argument -c
, and in the other case the command is the builtin eval
.
If you wanted to set test
to hello world
, you'd have to arrange for the inner shell evaluation to get an input like export test="hello world"
or export test='hello world'
or export test=hello\ world
. Note that there is no direct method that works for arbitrary characters in the value: surrounding with single quotes fails if the string contains single quotes; surrounding with double quotes fails if the string contains any of `"\[
; adding backslashes requires adding them before each of bunch of characters, and doesn't work for newlines. How to work around this difficulty depends on what you want to do. Many answers are to be found among quoting questions on this site.
However, this may not be what you want — it's not clear what you actually want to do. Note that the code is executed by the same shell. That's the whole point of source
or eval
: to execute code inside the same program. You're showing an example with source
where you read a file that starts with a shebang, but that shebang line is ignored, since the file isn't being executed: only its contents are.
If you want to construct the value of a variable using one program (e.g. zsh) while using another shell (e.g. bash), forget about all that and make the other program print the value. The simple way is:
test=$(zsh -c 'echo "hello world"')
Note that command substitution removes trailing newlines. So the value of test
will be the 11-character string hello world
, without a newline at the end. If you want to get the full output from echo
with the trailing newline, add another character (and optionally a newline) at the end, then strip it out.
test=$(zsh -c 'echo "hello world"'; echo .); test=${test%.}
source
, the file is executed as a bash script, not in zsh (the#!
is ignored).