7

I'm running bash, and my ~/.inputrc contains set editing-mode vi. This allows me to edit my command line using vi-like behaviour. And I can press v in normal mode to enter the full-fledged vi-editor, if I need full power to edit the command.

The only problem is that when I exit, the command executes right away. I would rather continue editing on the command line so that I can take advantage of bash's completion features. I can't do that when I'm in the vi editor. Is there a way to avoid automatically executing the edited command upon exiting vi?

3 Answers 3

7

I often just prepend the command with #. After exiting vim it's then in the bash history.

0
4

How to do it

Bash doesn't seem to provide builtin support for this in form of a readline function like it does for editing and executing. However, there is bind -x command to invoke arbitrary shell function and $READLINE_* variables which can be combined to perform command-line editing, one just needs to call Vim to do the job:

function _editcommandline() {
    local tmp_file="$(mktemp "/tmp/bash-editinplace.XXXXXX")"
    echo "$READLINE_LINE" >| "$tmp_file"

    vim +"call cursor(1, $READLINE_POINT + 1)" "$tmp_file"

    READLINE_LINE="$(< "$tmp_file")"
    READLINE_POINT="${#READLINE_LINE}"

    rm -f "$tmp_file"
}
# bind to Ctrl-X+e combination
bind -x '"\C-Xe": _editcommandline'

How it works

Here we define function _editcommandline() and use bind to tell bash to invoke it when C-Xe combination is pressed.

Inside the function:

  1. Temporary file is created.
  2. The file is filled with current input line.
  3. Vim is called to edit the line, positioning the cursor appropriately.
  4. Current line is replaced with contents of the temporary file, which is later removed.
  5. Cursor is positioned at the end of input line.

Limitation

The limitation of this approach is that you can edit only current input line, not whole command-line, but this is important only for multi-line commands.

Possible improvements

The function was written for demonstration purposes and can be further improved by:

  1. Correctly positioning cursor in bash instead of moving it to the end.
  2. Checking exit code of Vim to be able to discard saved changes with :cquit.
2
  • Thanks, xaizek. I have to admit, the answer is a bit more complicated than I was looking for.
    – user36800
    Commented Jun 5, 2017 at 0:12
  • This is a great answer. If someone wants to avoid to create a temp file you can use vipe from moreutils. Something like READLINE_LINE="$(echo"$READLINE_LINE" | vipe)"
    – durum
    Commented May 29, 2020 at 9:43
2

I have the following command in my .bashrc to do a similar thing:

set -o vi
3
  • That works for bash only. Other apps may read .inputrc, e.g., octave.
    – user36800
    Commented Jun 5, 2017 at 0:09
  • 1
    It works for ksh and csh as well Commented Jun 6, 2017 at 14:04
  • 1
    The comment as about putting a command into a single common file that affects as many apps as possible. So .inputrc seems preferrable to .bashrc.
    – user36800
    Commented Jun 7, 2017 at 14:50

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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