Why does command substitution with a command in front e.g. eval interprets the string as literal zsh commands to execute?
Asked Answered
D

1

-1

I was going through this What is the use of eval `opam config env` or eval $(opam env) and their difference? and notice something funny. I understand command subtitution is used to nest commands in zsh by evaluating a zsh cmd in a subshell and then giving it to the output as input to the command in front e.g.

eval $(cmd)

runs cmd replaces $(cmd) and gives it to the command eval. But when eval is not there is actually tries to interpret at string literal commands which to me is odd because if I gave that literal string to the termianl it would evaluate it just fine. e.g.

(iit_synthesis) brandomiranda~ ❯ $(echo v=1)
zsh: command not found: v=1
(iit_synthesis) brandomiranda~ ❯ v=1
(iit_synthesis) brandomiranda~ ❯ echo $v
1

interprets v=1 as a command to run but if I would have typed v=1 it would have evaluated and set the variable just fine. So what is the implicit command $(echo v=1) is giving to?

e.g. if I added eval in this case it would have worked which is strange to me. I would have expected that if $(echo v=1) just returns the string v=1 which is what we are echoing and then runs it in the terminal.

Note, eval at the front does work:

(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

related:

Dannettedanni answered 8/6, 2022 at 15:50 Comment(0)
H
2

You fell victim to the difference between a command and a command line.

Think about the command line

v=1 foo bar

This command line (or: statement, if you prefer this word) would run the command foo in an environment, which has the variable v assigned (in addition to the environment variables of the parent process).

Now imagine you have in your PATH an executable file named v=1 (which is possible, because nothing forbids you to use an equal sign inside a file name). If you wanted to execute this file, you can not simply write

v=1 x y

because this would run the command x and not v=1. Instead you have to write

'v=1' x y

or

command v=1 x y

or, if you prefer, using parameter expansion

cmd='v=1'
$cmd x y

All three variants tell the parser, that the command to be executed, is really the file v=1.

In the example from your question, you wrote

$(echo v=1)

which means that you first produce v=1 on standard output, and by command substitution run it as command. This command substitiution is similar to my previous example (where I used $cmd to do parameter expansion).

OTOH, if you would do a

eval $(echo v=1)

the output (v=1) is not executed as command, but as a full command line, i.e. as if you just had typed

v=1

on the command line, and it is parsed according to the zsh rules of parsing a command line. Therefore, v=1 is interpreted as variable assignment, and not as command.

Heteroecious answered 9/6, 2022 at 7:44 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.