8

I wrote a utility in bash that uses read -e to provide a prompt for sql-like queries. Sometimes these are long, so I want to be able to open vi, edit the current line and upon exiting, replace the line with the contents in vim. I read lines with read. Something like:

query> select .... from .... very long... <ctrl-e> 

now in vi

select .... from .... very long...

edit to

select ...
from ....
very long ...

exit vi

query> select ...
from ....
very long ... <enter>

query runs.

UPDATE: using 'set -o vi' before the 'read -e' seems to be the way for me, but currently when I click <esc>v the buffer that opens doesn't contain what is on the line but some other query, from my history (but not the one I typed before).

4
  • 1
    If you are using Oracle SqlPlus it is DEFINE _EDITOR = vim but I guess you have to add in your question which database system you are using. – hschou Mar 22 '17 at 11:01
  • 2
    Is this from a shell script, as implied from your tags? And using Bash's built-in read command? – Toby Speight Mar 22 '17 at 12:07
  • 2
    "a utility that accepts sql-like queries" -- What utility? Ambiguity is bad. As you can see, both the current answers are about bash, not your "utility". – phemmer Mar 22 '17 at 12:32
  • You might want to take a look at the dbext plugin. – Satō Katsura Mar 23 '17 at 8:42
13

First you have to make sure to use vi as shell command line editor:

set -o vi

Now you can type/copy your command to the command line. To leave insert mode and enter normal mode, use Esc or Shift+Tab. Now you can open vi by pressing v.

In vi, you can now do all the changes you want, save the buffer and exit vi, and the command gets executed.

4
  • 2
    That works in many shells, but does it work in a program that uses GNU Readline? I tested with psql and also other interactive programs. It doesn't work, even if I wrap it with rlwrap. – Kusalananda Mar 22 '17 at 9:38
  • 1
    It's not clear to me if the OP is doing this in the shell or at a prompt of an external utility. – Kusalananda Mar 22 '17 at 9:40
  • I'm doing this in a utility that i wrote – IttayD Mar 23 '17 at 9:26
  • tried this. when i type 'v' it indeed goes to vi, but not with the line I'm currently editing – IttayD Mar 23 '17 at 10:15
9

In bash, you can invoke an editor for the current command line using Ctrl+x, Ctrl+e.

On the system I have to hand, this isn't in the docs under man readline itself, but is in man bash under the "readline" section, so I'm not sure if it's a bash-specific feature, or if other readline-based programs would support it.

Here is the documentation from bash:

edit-and-execute-command (C-xC-e)

Invoke an editor on the current command line, and execute the result as shell commands. Bash attempts to invoke $VISUAL, $EDITOR, and emacs as the editor, in that order.

4
  • 1
    Just a note - to make the read builtin use the interactive readline settings (including the edit-and-execute-command binding), you need to invoke it as read -e. BTW, I have confirmed that this works. – Toby Speight Mar 22 '17 at 12:05
  • Is there a way to : edit in $VISUAL, and return to prompt but not execute straight away? – Olivier Dulac Apr 27 at 13:42
  • 1
    @OlivierDulac I don't know of a "clever" way, but a simple way is to put a # at the beginning of the command to make the whole thing a comment. Then when it's "executed", it won't do anything, but will be in the history, so you can press up and edit it again. – IMSoP Apr 27 at 13:49
  • @IMSoP: I .... I am ashamed I didn't think of that ^^ thanks! – Olivier Dulac Apr 27 at 14:31
5

As long as your prompt is a shell prompt (e.g. a call to read) all the other answers are valid and useful

If it isn't (you are not completely clear in this respect), e.g. when you are using a SQL interpreter xxxsql you can use rlwrap --multi-line -a xxxsql and then use a special (configurable) key to invoke the editor of your choice (specified by e.g. export RLWRAP_EDITOR="vim '+call cursor(%L,%C)" on the input -- the call_cursor is useful to preserve the cursor position when invoking vim)

As an extra perk, you will have full command history even for the multi-line commands (which are "compressed" into single-line ones before they are put on the history list, but expanded again when they are re-used)

edit: more information can be found on rlwraps Github page. Like all commands that use the GNU readline library most of its behaviour is specified in the users $INPUTRC to which rlwrap has added a number of its own options that control, among other things, the above-mentioned special key to invoke an external editor (CTRL+^ by default)

6
  • This seems like a good approach, but the instructions seem incomplete: what is the "special key" by default, and where do you configure it? And is rlwrap part of a separate package I need to install? It isn't present on the couple of Linux boxen I have in front of me. – IMSoP Mar 22 '17 at 21:19
  • I extended my answer a bit to make it more complete. rlwrap is not Linux-specific, but it can be found in most distributions (not usually installed by default). – Hans Lub Mar 22 '17 at 22:21
  • I agree with IMSop, this seems like the best approach. But it is missing the fact that rlwrap can be used entirely in vi mode. If you add set editing-mode vi inside ~/.inputrc then rlwrap will respect that and your rlwrap xxxsql (e.g. rlwrap sqlite3) will use vi mode. There is no need for RLWRAP_EDITOR hacks. – grochmal Mar 22 '17 at 23:29
  • Utilities such as psql for postgres, and mysql for mysql, have native support for readline, which will work a lot better than trying to use rlwrap. sqlplus unfortunately does not. – phemmer Mar 23 '17 at 1:04
  • @grochmal: The question was about multi-line editing. Even readline-aware commands may need rlwrap for that (and then, set editing-mode vi will not determine the editor used for multi-line edits) – Hans Lub Mar 23 '17 at 8:08

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