If i wanted to set the value of foo to equal bar everytime I used git status
how would I proceed to do this? My first thought would be to set an alias for status="status && foo=bar"
but when I attempt that and echo $foo I do not get bar echoed however if I type it all out manually as git status && foo=baz
and then echo $foo
my output is baz. Why can't I declare the variable inside the alias? Also I've observed that if I were to switch the order up and for some reason do this alias git="foo=bar && git"
and if I tried any git command and echoed foo it equals bar...
CodePudding user response:
Git aliases are run by:
- Git itself, if the alias does not start with
!
: in this case you cannot set new environment variables; or - a POSIX-compatible shell, if the alias starts with
!
.
POSIX-compatible shells allow setting environment variables in two ways:
VAR=value command
or:
VAR=value; export VAR; command1; command2; ...; commandN
This second variant can be written as:
export VAR=value; command1; ...; commandN
The explicitly exported variable is set for all the commands invoked this way—versus the VAR=value command
, which sets it just for the one command—because this setting is done in the shell, and persists until the shell itself exits, and then the setting disappears with the shell that has exited. So if x
is a Git alias:
git x
runs that alias, which can set an environment variable setting for the duration of any commands the alias itself runs. Then the shell that is running those commands exits, and all settings evaporate.
It's therefore literally impossible for a Git alias to set any environment variable in the command-line shell you use to run that alias. This is true for all commands, not just Git commands: no command can set environment variables in any "outer" shell.
There is one escape hatch, which is this: when you write a shell command yourself, you have control. For instance, you can write the rather silly shell command:
export VAR=$(echo value)
where the parenthesized $(echo value)
is evaluated and then its output is substituted in. But this does mean that if some program prints some value you would like to save, you can write:
var=$(command)
which sets the local shell variable var
to the output, or:
export VAR=$(command)
which sets the shell variable and exports it. (Note: the uppercase here is merely convention: local shell variables that are exported are conventionally written in all uppercase, while local shell variables that are not exported are conventionally written in all lowercase.)
There is a second escape hatch as well, but using it is risky: POSIX shells have an eval
command which feeds text back to the shell interpreter. We can use this with programs that print export VAR1=value1; export VAR2=value2
as their output:
eval `ssh-agent -s`
Here, the ssh-agent
program sets up the agent and then prints several appropriate export
commands. However, should the ssh-agent
program print rm -rf /
, using eval ssh-agent -s
will proceed to remove every file it can: this means you are placing a tremendous amount of trust on that ssh-agent
command.
You can use a shell alias to make some easy-to-type-in command, such as gst
, consist of both a variable-setting operation and a Git command:
alias gst='foo=bar && git status'
This is not a Git alias. This is a bash alias. Not all POSIX-compatible shells have shell aliases.
CodePudding user response:
- Regarding your shell's behavior :
If you write the following script :
# test.sh:
#!/bin/bash
foo=bar
echo "from script: $foo"
and you run it, you will see the following :
$ ./test.sh && echo "from cli: $foo"
from script: bar
from cli:
running the script creates a fresh, new process with its own environment, foo=bar
gets defined in that environment, and gets thrown away once the process exits.
To define set that variable in your current shell, you have to use other ways.
@torek mentioned :
- calling
eval ...
with the output of your script - creating a shell alias
I'll also add :
- invoke a function rather than a script :
$ mytest () {
foo=bar
echo "from function: $foo"
}
$ mytest && echo "from cli: $foo"
from function: bar
from cli: bar
- Regarding git aliases :
git alias will always be executed as separate processes, you will have to use some other construct if you want to set an env variable that "outlives" the invocation.
You can for example define a function in your .bashrc
:
mystatus () {
git status && foo=bar
}
after that, you will be able to call mystatus
from any shell you start.
If the command is that simple, it is really equivalent to a bash alias, the upside is that it will be easier to expand the content of that function if you need to.