How to source some shell code not a file?

There is a description of a source command:

source is a bash shell built-in command that executes the content of the file passed as argument, in the current shell. It has a synonym in . (period).

For example, for the sake of an experiment, I want to export a variable from a different shell zsh in my case (running the command in bash):

$ zsh -c "export test=$(echo "hello world")"
$ echo $test

$

It does not work because the command runs in a zsh subshell and is not executed directly in bash.

If I create and source a script this way:

#!/home/linuxbrew/.linuxbrew/bin/zsh

export test=$(echo "hello world")
$ chmod 777 test.zsh
$ source test.zsh
$ echo $test
hello world

It works alright.

The question is how to source a command without using a script since source can be run with files only?
I want to achieve something like that:

source zsh -c "export test=$(echo "hello world")"

If it is not possible, please explain why.

Asked By: t7e

||

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 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%.}

It might be simpler to have your command write out the variable’s definition and then to source that using process substitution:

$ echo $test

$ . <(echo "test='hello world'")
$ echo "$test"
hello world
Answered By: terdon
Categories: Answers Tags: , , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.