Normally, it is possible to set an environment variable for a command by prefixing it like so:
hello=hi bash -c 'echo $hello'
I also know that we can use a variable to substitute any part of a command invocation like the following:
$ cmd=bash
$ $cmd -c "echo hi" # equivalent to bash -c "echo hi"
I was very surprised to find out that you cannot use a variable to prefix a command to set an environment variable. Test case:
$ prefix=hello=hi
$ echo $prefix # prints hello=hi
$ $prefix bash -c 'echo $hello'
hello=hi: command not found
Why can I not set the environment variable using a variable? Is the prefix part a special part? I was able to get it working by using eval in front, but I still do not understand why. I am using bash 4.4.
Best Answer
I suspect this is the part of the sequence that's catching you:
That's from the Bash reference manual in the section on Simple Command Expansion.
In the
cmd=bash
example, no environment variables are set, and bash processes the command line up through parameter expansion, leavingbash -c "echo hi"
.In the
prefix=hello=hi
example, there are again no variable assignments in the first pass, so processing continues to parameter expansion, resulting in a first word ofhello=hi
.Once the variable assignments have been processed, they are not re-processed during command execution.
See the processing and its results under
set -x
:For a safer variation of "variable expansion" -as- "environment variables" than
eval
, consider wjandrea's suggestion ofenv
:It's not strictly a command-line variable assignment, since we're using the
env
utility's main function of assigning environment variables to a command, but it accomplishes the same goal. The$prefix
variable is expanded during the processing of the command-line, providing the name=value toenv
, who passes it along tobash
.