$_ vs !$. Last argument of the preceding command and output redirection

The question is about special variables. Documentation says:

!!:$

designates the last argument of the preceding command. This may
be shortened to !$.


($_, an underscore.) 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 command after expansion. Also set to the full pathname used to invoke each command executed and placed in the environment
exported to that command.

There must be some difference I cannot catch, because:

$ echo "hello" > /tmp/a.txt
$ echo "!$"
echo "/tmp/a.txt"
/tmp/a.txt

$ echo "hello" > /tmp/a.txt
$ echo $_
hello

What is the difference?

Answers:

Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.

Method 1

!$ is a word designator of history expansion; it expands to the last word of the previous command in history. In other words, the last word of the previous entry in history. This word is usually the last argument to the command, but not in case of redirection. In:

echo "hello" > /tmp/a.txt

the whole command 'echo "hello" > /tmp/a.txt' appeared in history, and /tmp/a.txt is the last word of that command.

_ is a shell parameter; it expands to the last argument of the previous command. Here, the redirection is not a part of arguments passed to the command, so only hello is the argument passed to echo. That’s why $_ expanded to hello.

_ is no longer one of shell standard special parameters. It works in bash, zsh, mksh and dash only when interactive, ksh93 only when two commands are on separated lines:

$ echo 1 && echo $_
1
/usr/bin/ksh

$ echo 1
1
$ echo $_
1

Method 2

I found it difficult if not impossible to use parameter substitution directly with !$.

For example if I could wget http://foo.com/my.tar then tar xf ${_##*/} but with !$ it is not possible without defining an intermediary variable.


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x