8 of 10 Figured out how $_ could be more useful than !$

man bash, search for section Special Parameters. For _ you'll find:

expands to the last argument to the previous command, after expansion.

So in a command line context the difference is the expansion. For example if I have a variable FOO set to 'bar' and I execute echo $FOO then $_ on the next line will result in bar being submitted in the next command while !$ will result in $FOO.

This behavior might not be obvious by default but with shopt -s histverify it's a little more evident. (With histverify enabled Bash will not submit history expansion immediately after Enter, it will first display the command, post-expansion, and wait for a second Enter). So we would see something like this after FOO=bar:

$ echo $FOO
$ ls !$ $_
# We hit Enter and then see
$ ls $FOO $_ 

$_ is not expanded until the command is submitted during parameter expansion (along with $FOO). It's a subtle distinction but there you go.

Probably the more interesting/useful distinction is that $_ is a variable. So, for example, if the last parameter were /some/file/path.txt you could get it's length ${#_} -> 19, extract filename only ${_##*/} -> path.txt, change the root ${_//some/other} -> /other/file/path.txt and so on. Can't do all of that with !$.

Note that $_ has different meanings in other contexts:

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.


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.