wcarroll wcarroll - 1 year ago 121
Bash Question

zsh bindkey with history

In short I'd like to map

Ctrl + 2
to the second most recently logged command in my .zsh_history file. Normally I would type
to achieve this. However, to recreate this behavior in a shell function I wrote the following:

function two_back {
command=$(history | tail -n 2 | head -n 1 | cut -c 8-)

echo -n "$command"

This outputs the value that I would expect, so it seems fine to me. In fact, If I just run the function
and press
it works as expected. The issue seems to reveal itself after I bind the function to some keystrokes.

First I convert the function into a zsh widget, so that I can bind it to some keystrokes...

$ zle -N two_back_widget two_back

Then I use the
command to create the mapping...

$ bindkey '^@' two_back_widget

Now when I type
Ctrl + 2
my z-shell line editor
contains the output that I expect. But when I attempt to run the command by pressing
nothing happens... Can anyone else reproduce this? And does anyone know why this isn't working?

Answer Source

The reason this is not working is, that while the command was printed to the terminal (output) it was not written in the terminal (input).

In order to actually enter the command like it has been typed into the shell this should work:

function two_back {
   command=$(history | tail -n 2 | head -n 1 | cut -c 8-)


zle -N two_back_widget two_back
bindkey '^@' two_back_widget


  • Within zle widgets BUFFER contains the current command line. It can also be modified. In this case BUFFER is set to the value of command. Writing to BUFFER effectively edits the current command on the command line.
  • CURSOR contains the cursor position on the command line. By setting it to the lengt of BUFFER the cursor will be placed at the end of the input. This is not strictly necessary, without setting it the cursor will remain in the same place. If the command line was previously empty the cursor will be on the very left of the command.