4

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?

3 Answers 3

4

$_ 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 _=':'
4

export -p does not show $_ for the simple reason that the command only shows those variables marked for export, and $_ (being a special parameter and not a variable--yes, the bash documentation makes that distinction) is not marked for export by the shell. While you can assign to _, bash will overwrite its value after each command. bash also seems to prevent, or at least undo, any attempt to explicitly export _.

1

From help export:

  -p    display a list of all exported variables and functions

Which would imply that $_ is simply not exported. That also makes sense since $_ is the last argument of the previous command exporting it to a separate shell would not be very useful since it will always be automatically reset depending on the last command run.

You can confirm that the commands you tried only list exported variables:

$ export -p | wc -l
41
$ foo="bar"
$ export -p | wc -l
41
$ export foo="bar"
$ export -p | wc -l
42

To see the full list of currently set variables (exported or not), use set with no arguments. This, however, will also list functions so you'll need to filter those out:

$ set | grep -P '^\S.*=' | wc -l
83
$ foo=bar
$ set | grep -P '^\S.*=' | wc -l
84
7
  • It doesn't have to exported to a separate shell, it is just a question of whether it exists as an environmental or otherwise variable in the current one.
    – Graeme
    Commented Mar 5, 2014 at 17:51
  • @Graeme not sure what you mean. export -p lists exported variables only and $_ is not exported.
    – terdon
    Commented Mar 5, 2014 at 17:58
  • '$_ is the last argument of the previous command exporting it to a separate shell would not be very useful since it will always be automatically reset depending on the last command run.' - this was what I was looking at.
    – Graeme
    Commented Mar 5, 2014 at 18:27
  • @Graeme exactly, I don't see the point of exporting that variable to child/separate shells which is, I guess, why it's not exported.
    – terdon
    Commented Mar 5, 2014 at 18:29
  • 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?
    – Nykakin
    Commented Mar 5, 2014 at 19:46

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .