Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Bash history expansion with tab completion

I make frequent use of command history expansion using the form !n:m, where n is the number of the historical command and m is the number of the argument, or short forms thereof.

Is there a way to expand such arguments in situ, so that I can then tab-complete them?

A trivial example:

$ mycmd long/path/with/plenty/of/subdirectories/
$ cp !$/tediously-verbose-filename.txt .

I'd love to be able to use argument repetition without having to then type the filename out in full (or resort to dummy runs with ls or echo).

like image 619
Alaya Avatar asked Apr 02 '14 21:04

Alaya


2 Answers

Not exactly what the OP wants, but you could use readline shortcuts to retrieve a specific argument from a prior command, and the shortcut is Alt+.. For the specific example that OP gave, this works very well, with the following workflow:

$ mycmd long/path/with/plenty/of/subdirectories/
$ cp <Alt>+./tediously-verbose-filename.txt .

Here are a couple of additional things that I find very useful:

  • If you continue to press Alt+., it retrieves the last argument from prior commands in the history.
  • You can prefix Alt+. with Alt+<n> where n is a digit from 0-9 to retrieve the specific argument. E.g., Alt+0Alt+. would retrieve the command itself and Alt+1Alt+. would retrieve the first parameter etc. You can then continue to press Alt+. without having to repeat the prefix.

NOTE: On terminals where Alt combination doesn't work, you could use Esc prefix, e.g., <Esc>..

like image 83
haridsv Avatar answered Oct 20 '22 03:10

haridsv


The conceptual terms you're looking for is [command] history and history expansion - if you run man bash, you'll find sections HISTORY and HISTORY EXPANSION devoted to this topic.

That said, in this particular case, it is not history expansion, but the special shell variable $_ that is your friend:

It expands to the last (expanded) argument of the most recent command.

Try the following, which mimics your scenario:

ls "$HOME"  

# Type this on the command line and press TAB (possibly twice)
# _before_ submitting to TAB-complete to matching files in "$HOME"
# (irrespective of what the current directory is).
# $_ at this point contains whatever "$HOME" expanded to, e.g. "/Users/jdoe".
cp $_/  

Note: Whether tab-completion works for a given command is unrelated to whether $_ is used or not. See man bash, section Programmable Completion, for how to manually enable tab-completion for commands of interest.

like image 42
mklement0 Avatar answered Oct 20 '22 02:10

mklement0