8

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

8

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

0
5

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. 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)" 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. 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. Commented Jun 7, 2017 at 14:50

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.