tldr: it activates your opam context according to your current switch -- similar to how a python virtual env is activated in python but for opam.
What eval $(opam env)
does is command substitute $(opam env)
i.e. run opam env
in a subshell (that's what $( )
does) return the string it outputted and then give it to eval
to evaluate as bash code. Command substitution is usually done to next the output of commands in bash. In python eval
would interpret the input string to it as literal python code to evaluate, parse, run here similarly it would do the same but assume it's bash (is my guess).
What does opam env
does? It returns the current bash env variables for the current swithc (i.e. siwth approximately euqal to opam environment). So therefore, doing:
eval $(opam env)
does this:
- first runs in a subshell because thats what
$(cmd)
does. It's command substitution. Usually used to nest commands.
- then it's output (so the output string of
$(opam env)
) is given to eval
. opam env
returns a string of env variables needed to "activate: the current opam env (similar to how you activate virtual envs in python).
- finally
eval
evaluates the string it receives from the command substitution i.e. it parses the string as a bash command and runs it.
For compeleteness see the output of opam env
:
(iit_synthesis) brandomiranda~ ❯ opam env
OPAM_SWITCH_PREFIX='/Users/brandomiranda/.opam/4.12.1'; export OPAM_SWITCH_PREFIX;
CAML_LD_LIBRARY_PATH='/Users/brandomiranda/.opam/4.12.1/lib/stublibs:/Users/brandomiranda/.opam/4.12.1/lib/ocaml/stublibs:/Users/brandomiranda/.opam/4.12.1/lib/ocaml'; export CAML_LD_LIBRARY_PATH;
OCAML_TOPLEVEL_PATH='/Users/brandomiranda/.opam/4.12.1/lib/toplevel'; export OCAML_TOPLEVEL_PATH;
PATH='/Users/brandomiranda/.opam/4.12.1/bin:/Users/brandomiranda/miniconda/envs/iit_synthesis/bin:/Users/brandomiranda/miniconda/condabin:/usr/local/bin:/Users/brandomiranda/.opam/4.12.1/bin:/opt/homebrew/bin:/usr/bin:/bin:/usr/sbin:/sbin'; export PATH;
Comment on backard ticks:
Please note : The back ticks shown around opam env
after eval
are essential. They change the order of application, which is very important. The back ticks tells the system to first evaluate opam env
(which returns a string of commands) and then eval
executes those commands in the string. Executing them doesn’t return anything, but it initializes the Opam environment behind the scenes.
ref: https://ocaml.org/docs/up-and-running
also see:
All details that lead to this answer:
From the man page for opam env:
This is most usefully used as eval $(opam env) to have further shell commands be evaluated in the proper opam context.
see: https://opam.ocaml.org/doc/man/opam-env.html
Slightly more details:
Finally, to get all the pieces together, what is the difference between command substitution (e.g. $( ) or
) and evaluating an expression (e.g. eval string or eval $(cmd) ) (in bash mainly). Ref: https://unix.stackexchange.com/a/23116/55620. My understanding is that $( ) runs a command in a subshells and outputs the string so that it's string is an input to another command e.g. eval. So to my understanding you can think of $(cmd) as replacing that expression and pasting the string of it back to to the command line for another commadn e.g. eval. While eval will take in the string and evaluate the expression in it instead. So what eval $(cmd) does is first evaluate $(cmd) replace it with the output string of running cmd in a subshell and then feeding it to eval -- where eval will pretend that input is code and evaluate it, parse and run it. So $(...) is usually done to nest command inside other commands.
The only puzzling thing to me is why $(cmd) without a cmd2 (eg eval) in the front interprets the strings of $(cmd) as bash commands to run instead of just evaluting e.g.
(iit_synthesis) brandomiranda~ ❯ $(echo v=1)
zsh: command not found: v=1
but
(iit_synthesis) brandomiranda~ ❯ v=1
(iit_synthesis) brandomiranda~ ❯ echo $v
1
does evaluate my string v=1 and then run it.
Thus what eval $(opam env) does is command substitute $(opam env) i.e. run opam env in a subshell return the string it outputted and then given to eval to evaluate as bash code. In python eval would interpret the input string to it as literal python code to evaluate, parse, run here similarly it would do the same but assume its bash (is my guess)
Long answer with all details:
toolchain = In software, a toolchain is a set of programming tools that is used to perform a complex software development task or to create a software product, which is typically another computer program or a set of related programs. https://www.google.com/search?q=toolchain&oq=toolchain&aqs=chrome..69i57j0i512l9.209j0j7&sourceid=chrome&ie=UTF-8
(iit_synthesis) brandomiranda~ ❯ opam env
OPAM_SWITCH_PREFIX='/Users/brandomiranda/.opam/4.12.1'; export OPAM_SWITCH_PREFIX;
CAML_LD_LIBRARY_PATH='/Users/brandomiranda/.opam/4.12.1/lib/stublibs:/Users/brandomiranda/.opam/4.12.1/lib/ocaml/stublibs:/Users/brandomiranda/.opam/4.12.1/lib/ocaml'; export CAML_LD_LIBRARY_PATH;
OCAML_TOPLEVEL_PATH='/Users/brandomiranda/.opam/4.12.1/lib/toplevel'; export OCAML_TOPLEVEL_PATH;
PATH='/Users/brandomiranda/.opam/4.12.1/bin:/Users/brandomiranda/miniconda/envs/iit_synthesis/bin:/Users/brandomiranda/miniconda/condabin:/usr/local/bin:/Users/brandomiranda/.opam/4.12.1/bin:/opt/homebrew/bin:/usr/bin:/bin:/usr/sbin:/sbin'; export PATH;
so opam env
outputs a bunch of paths that are needed for the toolchain to work...perhaps here toolchain == opam? Based on What is the use of eval `opam config env` or eval $(opam env) and their difference? (question for eval opam config env
) I am inferring that what it means is that these are the bash env variables needed to "activate the ocaml/opam environment". Concluded that because opam env
outputs a bunch of env variables.
So running opam env
by itself only prints the output to the terminal the output of the command opam env
.
$ usually refers that the identifier is a variable. e.g. $x is the variable x while x in the terminal is literally the string x (or command x if it exists).
$(command) or command
is command substitution. So doing $(command) runs the output (e.g. the script that would have been printed to the terminal after running command) of command. I assume it's called command substitution because we substitute command with the output of it and try to run it. e.g. it says: In computing, command substitution is a facility that allows a command to be run and its output to be pasted back on the command line as arguments to another command in the wikipedia article so yes. https://en.wikipedia.org/wiki/Command_substitution
opam env = opam-env - Prints appropriate shell variable assignments to stdout. Returns the bindings for the environment variables set in the current switch, e.g. PATH, in a format intended to be evaluated by a shell. https://opam.ocaml.org/doc/man/opam-env.html note that same opam man page says This is most usefully used as eval $(opam env) to have further shell commands be evaluated in the proper opam context.
Finally, to get all the pieces together, what is the difference between command substitution (e.g. $( ) or
) and evaluating an expression (e.g. eval string or eval $(cmd) ) (in bash mainly). Ref: https://unix.stackexchange.com/a/23116/55620. My understanding is that $( ) runs a command in a subshells and outputs the string so that it's string is an input to another command e.g. eval. So to my understanding you can think of $(cmd) as replacing that expression and pasting the string of it back to to the command line for another commadn e.g. eval. While eval will take in the string and evaluate the expression in it instead. So what eval $(cmd) does is first evaluate $(cmd) replace it with the output string of running cmd in a subshell and then feeding it to eval -- where eval will pretend that input is code and evaluate it, parse and run it. So $(...) is usually done to nest command inside other commands.
The only puzzling thing to me is why $(cmd) without a cmd2 (eg eval) in the front interprets the strings of $(cmd) as bash commands to run instead of just evaluting e.g.
(iit_synthesis) brandomiranda~ ❯ $(echo v=1)
zsh: command not found: v=1
but
(iit_synthesis) brandomiranda~ ❯ v=1
(iit_synthesis) brandomiranda~ ❯ echo $v
1
does evaluate my string v=1 and then run it.
Thus what eval $(opam env) does is command substitute $(opam env) i.e. run opam env in a subshell return the string it outputted and then given to eval to evaluate as bash code. In python eval would interpret the input string to it as literal python code to evaluate, parse, run here similarly it would do the same but assume its bash (is my guess)
Eval vs $( ) details:
Playground 1
(iit_synthesis) brandomiranda~ ❯ clear
(iit_synthesis) brandomiranda~ ❯ $(echo v=1)
zsh: command not found: v=1
(iit_synthesis) brandomiranda~ ❯ v=1
(iit_synthesis) brandomiranda~ ❯ echo $v
1
Playground 2
(iit_synthesis) brandomiranda~ ❯ echo vv=2
vv=2
(iit_synthesis) brandomiranda~ ❯ $(echo vv=2)
zsh: command not found: vv=2
(iit_synthesis) brandomiranda~ ❯ eval $(echo vv=2)
(iit_synthesis) brandomiranda~ ❯ echo $vv
2
opam env
outputs? Whateval
does? – Deadwood$(...)
does and how it interacts with the commands you mentioned. – Vernopam env
in your terminal and see the output and check whateval
does. Voting to close this question – DerickderideThis is most usefully used as eval $(opam env) to have further shell commands be evaluated in the proper opam context.
in opam.ocaml.org/doc/man/opam-env.html what does it mean? – Vern$(command)
and`command`
in shell programming? – Unparliamentaryeval $(anything)
is buggy, and would be more correctly written aseval "$(anything)"
. Documentation that does not recommend the double quotes is faulty and should have bug reports filed against it. – Unparliamentary