Setting environment variables for multiple commands in bash one-liner

Let's say I have following command

$> MYENVVAR=myfolder echo $MYENVVAR && MYENVVAR=myfolder ls $MYENVVAR

I mean that MYENVVAR=myfolder repeats

Is it possible to set it once for both "&&" separated commands while keeping the command on one line?


Solution 1:

Assuming you actually need it as an environment variable (even though the example code does not really need an environment variable; some shell variables are not environment variables):

(export MYENVVAR=myfolder; echo $MYENVVAR && ls $MYENVVAR)

If you don't need it as an environment variable, then:

(MYENVVAR=myfolder; echo $MYENVVAR && ls $MYENVVAR)

The parentheses create a sub-shell; environment variables (and plain variables) set in the sub-shell do not affect the parent shell. In both commands shown, the variable is set once and then used twice, once by each of the two commands.

Solution 2:

Parentheses spawn a new process, where you can set its own variables:

( MYENVVAR=myfolder; echo  1: $MYENVVAR; ); echo  2: $MYENVVAR;
1: myfolder
2:

Solution 3:

Wrapping the commands into a string and using eval on them is one way not yet mentioned:

a=abc eval 'echo $a; echo $a'
a=abc eval 'echo $a && echo $a'

Or, if you want to use a general-purpose many-to-many mapping between environment variables and commands, without the need to quote your commands, you can use my trap-based function below:

envMulti()
{
shopt -s extdebug;
PROMPT_COMMAND="$(trap -p DEBUG | tee >(read -n 1 || echo "trap - DEBUG")); $(shopt -p extdebug); PROMPT_COMMAND=$PROMPT_COMMAND";
eval "trap \"\
[[ \\\"\\\$BASH_COMMAND\\\" =~ ^trap ]] \
|| { eval \\\"$@ \\\$BASH_COMMAND\\\"; false; }\" DEBUG";
}

Usage:

envMulti a=aaa b=bbb; eval 'echo $a'; eval 'echo $b'

Note: the eval 'echo...'s above have nothing to do with my script; you can never do a=aaa echo $a directly, because the $a gets expanded too early.

Or use it with env if you prefer (it actually prefixes any commands with anything):

echo -e '#!/bin/bash\n\necho $a' > echoScript.sh
chmod +x echoScript.sh
envMulti env a=aaa; ./echoScript.sh; ./echoScript.sh

Note: created a test script just to demonstrate usage with env, which can't accept built-ins like eval as used in the earlier demo.

Oh, and the above were all intended for running your own shell commands by-hand. If you do anything other than that, make sure you know all the cautions about using eval -- i.e. make sure you trust the source of the commands, etc.