When we run a command the last argument is saved in _
which we can access:
$ echo $_
Doesn't sound like a terribly useful feature. So why bother? Are there any practical applications?
It has interactive uses, and can be exploited to perpetrate "code golfing".
It can reduce code by avoiding the need for a temporary variable, like:
temp=$destdir/$outfile
cp $infile $temp
chmod go-w $temp
to
cp $infile $destdir/$outfile
chmod go-w $_
I don't see this $_
feature among the Special Parameters of POSIX; it is a Bash extension (possibly in other shells).
It is a badly implemented hack, which breaks when you set a debug
trap, as demonstrated by the following script:
#!/bin/bash
dbg()
{
:
}
echo abc
echo $_
trap dbg debug
echo abc
echo $_
The output under Bash 4.4.20 is:
$ ./underscore.sh
abc
abc
abc
dbg
You can see that when we enable the debug trap, $_
no longer takes on the expected value abc
after echo abc
. In the specification of $_
, "last command" literally refers to the most recently executed command, not the previous command in the command sequence.
You definitely don't want to be using this in any Bash program that anyone might ever want to debug with a debugger that is implemented with the help of the debug trap.
Interactive use of $_
is the same: refer to the last argument of the previous command. This raises the question: why would anyone use this instead of one of the commands M-_ or M-. which expand the same item into the command line?
The differences in $_
are that:
It is much more compact than the expansion of a long path.
When a command with $_
is recalled from history, it no longer refers to its own predecessor in history, but to whatever command was most recently executed. This can be exploited. We can recall and re-use a command that contains $_
to operate on the most recently used right argument, rather than to exactly repeat an old command with the same arguments.
The content produced by M. is based on the raw, unexpanded command line, whereas $_
produces the actual last argument of the previous command. We can show this difference like so:
$ echo a{b,c}
ab ac
$ echo $_
ac
$ echo a{b,c}
$ echo █
At the point indicated by the cursor block █
, type the M. command. Meta M may be Esc or the Alt modifier. The result is:
$ echo a{b,c}█
In other words, the raw non-whitespace last token a{b,c}
from the previous command is inserted, rather than the semantic item ac
. This looks like more of a GNU Readline feature than a feature of GNU Bash.
$_
for that though like line editor widgets that do the same or csh-style history expansion. For a start, that $_
(like all parameter expansions in bash) should be quoted ("$_"
).
Commented
Apr 7 at 8:22
$_
. Also, $_
is not in POSIX; I'm looking at the spect and don't see it among the Special Parameters.
I use it often in the combo
mkdir verylongdirectoryname
cd $_
$_
has several meanings. See Understand the meaning of `$_`$_
for the "Topic variable". However UNIX Shell is listed as using$?
as the "Topic variable". See: rosettacode.org/wiki/Topic_variable#UNIX_Shell$?
has pretty much nothing to do with Perl's$_
, or Python's_
...$?
is closer toerrno
in C. Those kinds of listings are always something to be taken with a grain of salt.$?
has a lot more to do with C'serrno
, than with something like Perl's$_
. The example there relies on awkwardly using the exit status to return the result of a computation. That's not a good idea to do, first, because the value range is really limited, and second, because the idea of the exit status is to tell if the command or function succeeded or failed.