85

This question is similar to Vim: execute current file?, but instead of executing the current file I want to execute only the current line.

Is this possible?

Ideally, I am looking for solutions which can have side effects in the outer shell.

For example, suppose I have the following line:

alias foo=bar

After running the command in Vim, if I start a shell with :sh, the alias foo is available, but if I quit vim using :q, then the alias is no longer available.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
merlin2011
  • 71,677
  • 44
  • 195
  • 329
  • Maybe someone thinks it belongs to superuser. – ceving Nov 09 '13 at 22:43
  • 7
    That should be request to move, not a downvote? Or am I misunderstanding stackoverflow rules? I put the question on SO because SO has a `vim` tag. – merlin2011 Nov 09 '13 at 22:45
  • 3
    This question is fine here, in my view it fits in "software tools commonly used by programmers". Vim and bash are exactly that... I don't think the downvotes are justified. – jbat100 Nov 09 '13 at 23:28
  • There is no way to change the environment of a parent process. Sorry. (And I don't know how you can change the environment of future shells, either.) – rici Nov 10 '13 at 00:01

7 Answers7

147

Sure thing, you can 'write' any content of the current file into the standard input of another program:

:.w !bash

Here . (the part before w) refers to the range of lines you are writing, and . is only the current line. Then you use !bash to write those lines to Bash.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Daan Bakker
  • 6,122
  • 3
  • 24
  • 23
  • This is great, but the output isn't persistent in the way that `:!bash [my commands]` would be (i.e. I can later issue `:!` and see the output again). Is there a way to adapt this to put the output in _that_ buffer (whatever it is)? – Alec Jacobson Aug 25 '15 at 22:10
  • 2
    @AlecJacobson You could try this: `yy` to yank the current line, then `:!"` to paste the contents of the current line into the Vim command-line. – Daan Bakker Aug 26 '15 at 00:58
  • 1
    nice, that works great for single lines. Your answer above works for entire selections, is there are a a trick for that? If I try yanking multiple lines I end up with a lot of `^M`s in a single command rather than multiple commands. – Alec Jacobson Aug 26 '15 at 14:40
  • 3
    I bound this command to `,r` in `~/.vimrc` with the following: `nnoremap ,r :.w !bash`. Now in command mode, to execute a line, move the cursor to that line and type `,r`. The output will be displayed right in the editor. – wsams Dec 12 '16 at 23:02
  • @DaanBakker, I would stress in the answer that the space is before, and not after, the question mark, because as you know it makes a lot of difference, and can be useful for one of the most useful tricks ever: the [write with sudo](https://stackoverflow.com/a/7078429/5825294) trick. – Enlico Oct 08 '20 at 17:46
  • Run `.w !sudo bash` to execute the current line as root. – nav Dec 27 '21 at 17:32
  • Wow! So simple and the only appropriate answer to this question. And still there have been answers that end in unwanted results. 6 years later. – void Feb 23 '22 at 09:51
44

I do this sort of thing all the time with:

:exec '!'.getline('.')

You can even create a mapping in your .vimrc:

nmap <F6> :exec '!'.getline('.')
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
cforbish
  • 8,567
  • 3
  • 28
  • 32
  • 3
    I like this answer. You can also do `@"` instead of `.getline('.')` to execute yanked text instead of one line. – ws_e_c421 Jan 11 '16 at 07:49
23

Move the cursor to that line, and in normal mode press:

!!bash<cr>
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Kent
  • 189,393
  • 32
  • 233
  • 301
  • 4
    This has the unfortunate effect of replacing the current line with the output, which is not desired. – merlin2011 Nov 09 '13 at 22:40
  • 2
    @merlin2011 if the external (bash) command has output, you don't want to display it in buffer? or you want it below the "current line"? – Kent Nov 09 '13 at 22:47
  • 1
    Below or suppressed are both okay. I am executing the command for its side effect rather than to get its output in this case. – merlin2011 Nov 09 '13 at 22:47
8

This could be a comment if I can comment.

Concerning redirect/pipe lines of current buffer in Vim to external command, inspired by Daan Bakker's great answer, I wrote I answer here (Save and run at the same time in Vim), on an question concerning running a Python script (current buffer).

Beside running the whole buffer, how to run a range of line via an external command is demonstrated.

To save time, I just copy it below.

#####################

In Vim, you could simply redirect any range of your current buffer to an external command (be it 'bash', 'python', or you own Python script).

# Redirect the whole buffer to 'python'
:%w !python

Suppose your current buffer contains the two lines as below,

import numpy as np
print np.arange(12).reshape(3,4)

then :%w !python will run it, be it saved or not. And print something like below on your terminal,

[[ 0  1  2  3]
 [ 4  5  6  7]
 [ 8  9 10 11]]

Of course, you could make something persistent, for example, some keymaps.

nnoremap <F8> :.w !python<CR>
vnoremap <F8> :w !python<CR>

The first one runs the current line. The second one runs the visual selection, via the Python interpreter.

#!! Be careful, in Vim ':w!python' and ':.w !python' are very different, the
first writes (creates or overwrites) a file named 'python' with thew contents of
the current buffer. The second redirects the selected cmdline range (here dot .,
which mean current line) to an external command (here 'python').

For cmdline range, see

:h cmdline-ranges

Not the below one, which concerning normal command, not cmdline one.

:h command-range

This was inspired by Execute current line in Bash from Vim.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
qeatzy
  • 1,363
  • 14
  • 21
5

Add this mapping to your .vimrc file,

nmap <leader>E yyp:.!csh<CR>

Explanation:

  1. yy Yank current line
  2. p Paste yanked line below (and the cursor goes to this next row)
  3. :.!csh<CR> Execute (using csh) this newly pasted line in place. The output of this line replaces this current line, thus before executing the line was yanked and pasted below.
Rohan Ghige
  • 479
  • 5
  • 11
1

If I have a command on a line of text within vi/Vim like this"

ls -la

Position the cursor anywhere on the line and do ":.!!" and press return.

That is: colon dot bang bang return

That will execute the text in that line in the current shell from within vi/Vim and have the output inserted within the text file.

I'm thinking that is what you were asking? It's like magic.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Brux
  • 31
  • 5
0

Consider the following command run on terminal,

seq 0 10 | xargs printf "%02x "

Expected output is,

00 01 02 03 04 05 06 07 08 09 0a

Consider you have this above command written in a file. To execute this command get this respective output back in that file, you can add this mapping in yours .vimrc,

nmap <leader>E :exec 'r!'.getline('.')<CR>

Note that, to execute above mentioned line, you need to write it with adding escape char for '%' as follows,

seq 0 10 | xargs printf "\%02x "

Go this line in your file and press <leader>E. In my case, <leader> is mapped to , hence I will press ,E

Rohan Ghige
  • 479
  • 5
  • 11