Usage of `_` as an environment variable passed to a command

environment-variables

From bash manual

_

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. Subsequently, expands to the last argument to the
previous command, after expansion. Also set to the full pathname used
to invoke each command executed and placed in the environment exported
to that command.
When checking mail, this parameter holds the name of
the mail file.

Regarding the sentence in bold, Stephane said that

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

How can I get the environment variable _'s value for an arbitrary command instead of env, to verify that its value is the pathname of the executable or script for the command?

Thanks.

Best Answer

The $_ value is visible to the child process. How you read it in the child is up to the language you use.

e.g. in C

#include <stdlib.h>
#include <stdio.h>

main()
{
  char *x=getenv("_");
  printf("%s\n",x);
}

However a program can not rely on $_ being set because other shells may do different things.

e.g.

$ env -i /bin/bash -c ./a.out
./a.out

$ env -i /bin/ksh -c ./a.out 
*31801*./a.out

$ env -i /bin/sh -c ./a.out 
Segmentation fault (core dumped)

/bin/sh (which is "dash" on this Ubuntu system) doesn't set $_ at all and so this simple program crashes. Oops :-)

Your calling program can't see this value of $_ at all. Indeed, in the calling shell $_ is set to the last parameter of the previous line

$ ls /tmp > /dev/null
$ echo $_
/tmp

$ echo hello
hello
$ echo $_
hello
Related Question