8

In Bash, there are some handy operators to repeat parts of the last command:

  • !^ expands to the first argument of the previous command, e.g.,

    $ echo one "two three"
    one two three
    $ echo !^
    echo one
    one
    
  • !$ expands to the last argument of the previous command, e.g.,

    $ echo one "two three"
    one two three
    $ echo !$
    echo "two three"
    two three
    
  • !* expands to all arguments of the previous command, e.g.,

    $ echo one "two three"
    one two three
    $ echo !*
    echo one "two three"
    one two three
    

(As far as I understand, these are syntactic sugar for !!:^, !!:$ and !!:* respectively, where !! is an event designator that expands to the previous command, and ^, $ and * are word designators, see the Bash Reference Manual or man bash.)

These are often quite handy. But it gets even cooler with keyboard shortcuts:

  • When you hit Alt+. or Alt+_, the last argument of the previous command is inserted in the current command, similarly as if you had written !$ at that point.

  • It is also possible to hit Alt+Ctrl+y to insert the first argument of the previous command, as if you had written !^ at that point.

(See the GNU Readline Library or info readline.)

I tend to prefer the keyboard shortcuts over Bash's history operators, because I can see what I'm inserting before I actually execute the command. However, there does not seem to be a shortcut that enables me to insert all the words of the previous command, i.e., one that does !*'s job. At least I could not find it.

Is there such a shortcut? If not, is it possible to configure the readline library to add one, and how?

  • AFAIK, keyboard shortcuts are handled by the terminal emulator. So I suppose you're using gnome-terminal? – Seth Mar 25 '14 at 18:37
  • 1
    In zsh, if you type echo !* and then press TAB, you have the desired effect. In general, TAB while in readline will expand all the expandable. Very handy; probably bash will have some configuration to the same effect? @Seth, I think this is the readline into bash, not the terminal emulator - not sure though. – Rmano Mar 25 '14 at 18:42
  • 2
    @Seth No, the shortcuts from the Q are handled by bash. You can serch for 'Commands for Manipulating the History' in man bash (somewhere at the line 3030) – Radu Rădeanu Mar 25 '14 at 18:50
  • @RaduRădeanu Oh interesting! I didn't know that. My bad for bad assumptions. – Seth Mar 25 '14 at 18:54
  • 1
    \e. and \e_ are mapped to readline function yank-last-arg and \e\C-y is mapped to yank-nth-arg. Sadly there seems to be no (single) command that adds multiple previous arguments at once. – Adaephon Mar 25 '14 at 20:30
5

If you look at the output of the following command:

bind -l

or better to:

bind -l | grep arg

you can see that doesn't exist any readline function for all arguments like is, for example, yank-last-arg for last argument - which can insert last argument to the previous command (the last word of the previous history entry). So, if such a function doesn't exists, most probably doesn't exist a shortcut to accomplish what you wish.

Let's try to crate one approached to your request...

First, look for example at the output of the following command:

bind -p | grep yank-nth-arg

The output is:

"\e\C-y": yank-nth-arg

and can be translated as follow: yank-nth-arg (which insert the first argument to the previous command - with an argument n, insert the nth argument from the previous command) is bound to Alt+Ctrl+y.

In the same way can be interpreted any line from the output of bind -p command.

Now play attention at the following scenarios:

  • If you set the following binding:

    bind '"\ea": "\e2\e."'
    

    Alt+A will be mapped to Alt+2Alt+. which is mapped to insert the second argument of the previous command. So, after when you press Alt+A, the second argument of the previous command is inserted in the current command.

  • If you set:

    bind '"\ea": "\e1\e. \e2\e."'
    

    After when you press Alt+A, the first two arguments of the previous command is inserted in the current command. If the number of the arguments from the previous command is maximum 2, of course all of the previous command is inserted in the current command.

  • If you set:

    bind '"\ea": "\e1\e. \e2\e. \e3\e."'
    

    After when you press Alt+A, the first three arguments of the previous command is inserted in the current command. If the number of the arguments from the previous command is maximum 3 (as in your case), of course all of the previous command is inserted in the current command.

  • And so on.

For first 10 arguments, you can use:

bind '"\ea": "\e1\e. \e2\e. \e3\e. \e4\e. \e5\e. \e6\e. \e7\e. \e8\e. \e9\e. \e1\e0\e."'

And I think that this is long enough as far as I don't use too often commands with so many arguments.

To make it persistent, add the following line line to your ~/.inputrc file:

"\ea": "\e1\e. \e2\e. \e3\e. \e4\e. \e5\e. \e6\e. \e7\e. \e8\e. \e9\e. \e1\e0\e."

In this example I chose Alt+A to insert all arguments (if the number of arguments is not greater than 10) of the previous command, but you can chose any other combination you with by replacing in the previous command the \ea string.

Resources:

  • Well, it's somewhat hackish, and it will only work for a limited number of arguments, but it seems to be the closest we can easily get -- I'll take it ;) Actually I just had a look at readline's source code. At first glance it looks like in the file funmap.c, the function yank-nth-arg is mapped to the C function rl_yank_nth_arg, which in turn is defined in kill.c. Analogously for yank-last-arg. Of course it would be possible to extend readline with such a functionality, but I don't want to do that; I prefer my readline to be managed by apt, and this feature not that important ;) – Malte Skoruppa Mar 26 '14 at 10:17

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.