Understand the meaning of `$_`
I agree it's not very clear.
1. At shell startup,
if the
_
variable was in the environment thatbash
received, thenbash
leaves it untouched.In particular, if that
bash
shell was invoked by anotherbash
shell (thoughzsh
,yash
and someksh
implementations also do it), then thatbash
shell will have set the_
environment variable to the path of the command being executed (that's the 3rd point in your question). For instance, ifbash
is invoked to interpret a script as a result of anotherbash
shell interpreting:bash-script some args
That
bash
will have passed_=/path/to/bash-scrip
in the environment given tobash-script
, and that's what the initial value of the$_
bash
variable will be in thebash
shell that interprets that script.$ env -i _=whatever bash -c 'echo "$_"' whatever
Now, if the invoking application doesn't pass a
_
environment variable, the invokedbash
shell will initialise$_
to theargv[0]
it receives itself which could bebash
, or/path/to/bash
or/path/to/some-script
or anything else (in the example above, that would be/bin/bash
if the she-bang of the script was#! /bin/bash
or/path/to/bash-script
depending on the system).So that text is misleading as it describes the behaviour of the caller which
bash
has no control over. The application that invokedbash
may very well not set$_
at all (in practice, only some shells and a few rare interactive applications do,execlp()
doesn't for instance), or it could use it for something completely different (for instanceksh93
sets it to*pid*/path/to/command
).$ env bash -c 'echo "$_"' /usr/bin/env (env did not set it to /bin/bash, so the value we get is the one passed to env by my interactive shell) $ ksh93 -c 'bash -c "echo \$_"' *20042*/bin/bash
2. Subsequently
The Subsequently is not very clear either. In practice, that's as soon as bash
interprets a simple command in the current shell environment.
In the case of an interactive shell, that will be on the first simple command interpreted from
/etc/bash.bashrc
for instance.For instance, at the prompt of an interactive shell:
$ echo "$_" ] (the last arg of the last command from my ~/.bashrc) $ f() { echo test; } $ echo "$_" ] (the command-line before had no simple command, so we get the last argument of that previous echo commandline) $ (: test) $ echo "$_" ] (simple command, but in a sub-shell environment) $ : test $ echo "$_" test
For a non-interactive shell, it would be the first command in
$BASH_ENV
or of the code fed to that shell if$BASH_ENV
is not set.
3. When Bash executes a command
The third point is something different and is hinted in the discussion above.
bash
, like a few other shells will pass a _
environment variable to commands it executes that contains the path that bash
used as the first argument to the execve()
system calls.
$ env | grep '^_'
_=/usr/bin/env
4. When checking mail
The fourth point is described in more details in the description of the MAILPATH
variable:
'MAILPATH'
A colon-separated list of filenames which the shell periodically checks for new mail.
Each list entry can specify the message that is printed when new mail arrives in the mail file by separating the filename from the message with a '?'. When used in the text of the message, '$_' expands to the name of the current mail file.
Example:
$ MAILCHECK=1 MAILPATH='/tmp/a?New mail in <$_>' bash
bash$ echo test >> /tmp/a
New mail in </tmp/a>
Try this simple example:
echo "$_"
echo "test"
echo "$_"
Run it by giving the absolute path (/home/$USERNAME/test.sh
); output:
/home/$USERNAME/test.sh
test
test
First $_
contains the path you used to invoke the script and the second one contains the first argument to the middle echo
.
For the third item in the list, if you start a new terminal and type echo $_
it will show the variable containing the PATH
which is usually used to lookup and invoke commands (in my Ubuntu machine) in a normal shell or absolute path to your .bashrs
file in a login shell.
For the item four from bash man page:
When used in the text of the message,
$_
expands to the name of the current mailfile.
For case 2, an example is worth a thousand words:
mkdir my_long_dir
cd $_
Does what you'd guess / hope for. Gives me a simple placeholder when I'm on the command line to save me having to repeate myself.