1

I know that with this command:

:yyp!!bash

I can execute current line and print the output in the next line (actually it copies the current line to the next line, executes it, and replaces it with the output), to get from this:

echo "Hello"

to this (after the command above):

echo "Hello"
Hello

I also know that I can use this command:

:w !bash

To execute the selected lines (plural) and show the output in the window below the editor.

What I want is to be able to select multiple lines, execute it in bash, and print the output in vim. How can I do that?

So desired behavior is to get from:

echo \
    -e "Hello\nWorld"
echo "Hi"

to:

echo \
    -e "Hello\nWorld"
echo "Hi"
Hello
World
Hi
  • 1
    Define “doesnt work”—also see my recent answer on sending lines to a terminal. Finally, consider using a custom operator – D. Ben Knoble Mar 18 at 16:38
  • Uh, the "doesn't work" part is only the bonus part. And in this case doesn't work means it just blink with no change. It doesn't seem to perform the command sequence as if I did that manually. – justhalf Mar 18 at 17:00
  • There’s a typo there: yp is not yyp – D. Ben Knoble Mar 18 at 17:00
  • Ah, I didn't know that shortcut doesn't work the same way as when we are selecting some lines? That command is supposed to be executed after I select a line (so just y is enough to copy). If I change it to yy and did not select a line, it works. My question still stand then, how to select a few lines, and then use a shortcut to perform the command. – justhalf Mar 18 at 17:03
2

When you have the lines selected you could just use the following:

yPgv:!bash

If you want to have that as a mapping you can do like that:

:xnoremap x yPgv:!bash<CR>

To be clear, do NOT use x here but insert your desired mapping. x would be a horrible idea, the cut function is pretty useful.

Breakdown:

y will copy the selected text

P paste before

gv reselect last visual selection

:!bash send it to bash

As you see, you had all the hard parts already there, which made it easy for me. Just a little lesson in vim trickery needed.

Explanation

The ! commands means filter all selected lines through an external program. In this case bash. see :h ! for information about that. So :! bash means send the lines to bash, and replace them with the output from bash.

You used :w !bash which is a write command (see :h :w). It does execute bash with the selected lines as the standard input. So vim just writes and does not directly read it back.

There is simple way I know of to get the results line by line. You could however call this command for every line. This would require some vimscript (see here for a starting point).

  • Ah, ok. I'm actually still not sure which part replaces the input with the bash output. What's the difference between :w !bash and :!bash? Why does the latter replaces the editor with the output? – justhalf Mar 20 at 8:50
  • Also, currently using this command vim seems to wait until bash is complete before putting the output into the editor. Is there a way to pipe the output of the bash command as it go? So we don't have to wait until completion to see some outputs being written back into the editor. Perhaps I should ask a separate question. – justhalf Mar 20 at 8:52
  • @justhalf please read the new Explanation part in my answer – Doktor OSwaldo Mar 20 at 9:15
  • Thanks for your updated answer! What I'm looking for is unfortunately not about executing line by line. See my new question for details. – justhalf Mar 20 at 9:23
2

I would propose the following:

nnoremap _X  :put =system(getline('.'))<cr>
vnoremap _X  :<C-U>'>put =system(join(getline('''<','''>'),\"\n\").\"\n\")<cr>

The first mapping is to execute a single line. Just put the cursor in the line and hit _X. This takes the current line (getline(".")), executes it (system(...)) and puts the returned result below the current line.

The visual mode mapping works similar, but

  • `getline('''<', '''>') fetches the list of selected lines
  • join(..., "\n")."\n" joins the list into one string
  • finally put puts the result below the last selected line, due to the leading `'>'
  • That seems much more complicated than the solution above. Do you know what are the advantages of doing this over using the other? Is it more generalizable somehow? – justhalf Mar 20 at 9:45
  • Advantage is that you don't copy anything to a register, so if you yanked something before, it's still there. The first mapping is not complicated. The second looks complicated as the double quotes need escaping, due to Vim handling them as comment sign. – Ralf Mar 20 at 9:53
  • 1
    This solution uses vimscript which leads to a more elegant solution. The reason why I choose another approach (vim normal mode commands) is, that I was able to use a lot of your prework (which has somewhat of an educational reason). It is correct that this solution leaves the registers intact. This will be an advantage in most of the cases! This solution is not more complicated than mine, I would say even easier but uses some functions of vim which you don't use everyday – Doktor OSwaldo Mar 20 at 12:21
  • Maybe a stupid question, but what is _X exactly? – Shanteva Aug 22 at 20:04

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.