Bash – Why does export -p exclude $_ variable

bashcommand lineenvironment-variables

As far I know, there are 3 ways to see exported variables:

$ export -p | wc -l
50
$ env | wc -l
51
$ printenv | wc -l
51

As you can see, export -p misses single variable. It's a $_ one:

$ diff <(export -p |sed 's/declare -x //' | sed 's/"//g' | sort) <(printenv | sort)
41a42
> _=/usr/bin/printenv

$_ is special variable set to final argument of previous command executed. Why export -p doesn't include it, unlike two other commands?

Edit

I understand that exporting $_ might not have any sense but if $_ is not exported then why it appears in printenv output? printenv prints environment variables, environment variables are exported ones, $_ is not exported. Am I missing something here?

Best Answer

$_ does not seem to be an environmental variable in bash, bash only appears to export it into a child process' environment. Inside bash itself it seems to be a normal shell variable. Note however this is not the case when the first command is executed:

$ bash -c 'export -p | grep _='
declare -x _="/bin/bash"

Afterwards however it shows up as a normal variable:

$ bash -c ':; declare -p | grep _='
declare -- BASH_EXECUTION_STRING=":; declare -p | grep _="
declare -- _=":

Not this is not the case in dash:

$ dash -c 'export -p | grep _='
export _='/bin/dash'
$ dash -c ':; export -p | grep _='
export _='/bin/dash'

Although here it only seems to take on its proper role in interactive mode:

$ dash
$ :
$ export -p | grep _=
export _=':'
Related Question