What does ${_[0]} mean in bash?
When I type this in bash command line
$ x=hi; printf '%s ' "$x" "${x[0]}"; echo "${_[0]}"
I have this output:
hi hi hi
- Why
"${_[0]}"
turns out to be"hi"
in the output?
- Why could we use the
"x[0]"
syntax, given that"x"
is just astring
instead of anarray
?
The _
parameter has several meanings depending on context, but it is never an array. Likewise, in your example, x
is not an array. The reason you're able to treat it as if it is an array is that Bash allows non-array variables to be treated as if they were one-element arrays. Bash likewise allows array variables to be treated as if they were non-arrays, giving the first element.
As man bash
says:
Referencing an array variable without a subscript is equivalent to referencing the array with a subscript of 0. Any reference to a variable using a valid subscript is legal, and
bash
will create an array if necessary.
So "${_[0]}"
behaves the same as "${_}"
or "$_"
, because _
is not an array. Likewise, "${x[0]}"
behaves the same as "${x}"
or "$x"
, because x
is not an array.
As for why _
holds the value hi
: In the usage you've shown, performing parameter expansion on the special _
parameter yields the last argument of the most recent (synchronously executed) command.
As man bash
says of _
:
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 simple command executed in the foreground, 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 currently being checked.
(emphasis mine)
In this case, the most recently executed command was:
printf '%s ' "$x" "${x[0]}"
The arguments passed to printf
were:
-
%s
, on which only quote removal was performed. -
hi
, on which parameter expansion was performed, followed by quote removal. -
hi
, on which a more complex form of parameter expansion yielding the same result was performed, followed by quote removal.
$_
is a special parameter. It is used in a number of ways but, in your case, it refers to the last argument of the previous command:
$ echo hi Hi Hello
hi Hi Hello
$ echo "$_"
Hello
Since $_
is a variable, not an array, the syntax ${_[0]}
is just useless clutter that accesses $_
:
$ echo "$_"
Hello
$ echo "${_[0]}"
Hello
Documentation
From man bash
:
$_
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 simple command executed in the foreground, 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 currently being checked.
I highlighted in bold the part relevant to your usage.
As others have mentioned ${_[0]}
is extra typing for ${_}
which in turn can be abbreviated into $_
as it is most commonly used.
As mentioned previously it is a variable that contains the last parameter of the last command used. A practical application is like this:
$ ll /etc/lsb-release
-rw-r--r-- 1 root root 105 Feb 20 2019 /etc/lsb-release
$ cat $_
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=16.04
DISTRIB_CODENAME=xenial
DISTRIB_DESCRIPTION="Ubuntu 16.04.6 LTS"
In the first command the last parameter is /etc/lsb-release
. In the second command the parameter is $_
, which repeats /etc/lsb-release
so you don't have to retype it.