8

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.

  • 3
    -1 question unclear & not thoroughly researched. What have you tried? Where did your expectations misalign with the text? Do you not honestly understand the word 'subsequently'? If a new user were to ask this same question I would have the same questions of them (despite my similar innate curiosity as to exactly how things work). – Jeff Schaller May 2 '16 at 2:41
16

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>
4

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.

  • 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? – Tim May 2 '16 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. – coffeMug May 2 '16 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 – coffeMug May 2 '16 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. – Jeff Schaller May 2 '16 at 9:47

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.