48

Could you explain the following sentences from Bash manual about $_, especially the parts in bold, maybe with some examples?

  1. At shell startup, set to the absolute pathname used to invoke the shell or shell script being executed as passed in the environment or argument list.

  2. Subsequently, expands to the last argument to the previous command, after expansion.

  3. Also set to the full pathname used to invoke each command executed and placed in the environment exported to that command.

  4. When checking mail, this parameter holds the name of the mail file.

0

3 Answers 3

47

I agree it's not very clear.

1. At shell startup,

  • if the _ variable was in the environment that bash received, then bash leaves it untouched.

    In particular, if that bash shell was invoked by another bash shell (though zsh, yash and some ksh implementations also do it), then that bash 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, if bash is invoked to interpret a script as a result of another bash shell interpreting:

    bash-script some args 

    That bash will have passed _=/path/to/bash-scrip in the environment given to bash-script, and that's what the initial value of the $_ bash variable will be in the bash shell that interprets that script.

    $ env -i _=whatever bash -c 'echo "$_"' whatever 
  • Now, if the invoking application doesn't pass a _ environment variable, the invoked bash shell will initialise $_ to the argv[0] it receives itself which could be bash, 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 invoked bash 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 instance ksh93 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> 
1
  • 4
    Also this old chestnut: mkdir somedirectory && cd $_ puts you right in the directory you just created. Commented Oct 23, 2020 at 20:52
13

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 repeat myself.


¹ at least here for a such a simple directory name and assuming $CDPATH is empty or unset and $IFS has not been modified from its default value. In the general case, you'd need something like mkdir -p -- $'-less tamed directory-/../foo/ *** Ah! *** /\n\n' && CDPATH= cd -P -- "$_", though that's orthogonal to this discussion.

1
  • 1
    But Alt+. is so much easier to type Commented May 28, 2024 at 10:16
11

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.

4
  • Thanks. (1) can you explain the third case with examples? (2) When I open a new gnome terminal tab, the output of echo $_ is EDITOR, and why is it? Which case does it follow? (3) Can you given an example of how to check mails, and of using $_ in this case? Commented May 2, 2016 at 0:00
  • Open your .bashrc and comment out every line there. Keep only a single line containing a command like echo "test" or similar. Save and close. Then run bash and immediately echo $_. This last echo should print test in the output. Commented May 2, 2016 at 6:50
  • For the mail part I have not used Unix mail and don't have a working mail installed on my system now so cannot give you example. But should be obvious if you follow the description of MAILPATH in linuxcommand.org/lc3_man_pages/bash1.html Commented May 2, 2016 at 7:18
  • 1
    FYI, the canonical, up-to-date version of the bash manual is: gnu.org/software/bash/manual/bashref.html . It's version 4.3 while the linuxcommand page was 4.1. Commented May 2, 2016 at 9:47

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.