I was unclear: I did not mean to imply that it will work with it.
It's OT, but I'll clarify since it might be useful for people who find Bash cryptic.
Thing is, roughly speaking:
eval
will evaluate its first argument as Bash code
eval "$(any_command really)"
will run run any_command really
, take its output and then use it as first argument for eval
. So the assumption is that any_command really
must output a valid Bash code snippet.
So what eval "$(ssh-agent -s)"
really means is, "run ssh-agent -s, collect the output and run it right here, where we are calling eval
. Compare to ssh-agent -s | bash
-- this would also run ssh-agent output but it would run it in a new process--a child process of the current process---so the whatever the snippet would be, it would have no way of affecting state of the parent program, which is why it's safer.
Aside: The reason we need eval in this case is that we actually need to affect state of the program: that's the whole point. We need to set several environment variables to values that ssh-agent "knows". Without eval
we would have to "ask" ssh-agent separately for each value (I'm assuming it's not even supported) and then set all these envvars using eg. export
keyword. Using eval
we let ssh-agent dictate the whole process: which variables are going to be set to what values, with the caveat that if compromised, it could do "evil" stuff like setting PATH
to override common commands with compromised code. etc.
So what's the problem with the quotes? The Shell syntax, foo "$(bar baz)"
will make sure that the thing between quotes is
- kept verbatim
- treated as a single argument, even if it contains newlines (with some ugly exceptions to this regarding the final newline)
Now without quotes, Bash (as well as POSIX shell) actually have several things they can do with the output (read man bash
for full list, but keep it for a long rainy evening). Some of it involves substituting eg. values like *
with matching filenames, some of it may involve actually splitting the output to separate arguments based on spaces or other special characters (which can even be different characters depending on current state, see IFS
and the likes).
You can see the difference, if you run eg. printf '[%s]\n'
instead of eval
. This printf syntax will simply print all of following arguments on a separate line, adding braces before and after. You can compare
printf '|%s|\n' $(ssh-agent -s) # printf will probably receive multiple extra arguments
printf '|%s|\n' "$(ssh-agent -s)" # printf will receive just one extra argument (and print it as specified)
(both of these commands should be safe as long as ssh-agent
is not compromised and as long I have not made any terrible typo)