15

I would like to edit content in vim which was dynamically generated from the command-line without having the file yet.

In example:

$ echo This is example. | vim /dev/stdin
$ cat /etc/hosts | vim /dev/stdin

but it's failing with the errors:

Vim: Warning: Input is not from a terminal

Vim: Error reading input, exiting...

It is possible to achieve that?

  • :help stdin... It's amazing how fast one can find the answers by asking their question of the built in documentation. – dash-tom-bang Mar 3 '16 at 20:07
23

You have to use - in place of the file name on the command line:

echo This is example. | vim -

The above command will open an unnamed buffer filled with the text read from the standard input.

  • 7
    Using a - for stdin is pretty much standard for commandline tools; – Martin Tournoij Feb 12 '15 at 17:15
6

This is just mostly a fun note about bash and readline, but if you set your EDITOR environment variable to vim, hitting Ctrl+x+e will open up the current line in vim. Further, if you type Meta(Alt/Opt/Esc)+Ctrl+e, bash will perform an in place expansion on the current command line, i.e.:

$ echo $EDITOR # Assuming EDITOR was set

with Meta(Alt/Opt/Esc)+Ctrl+e would become

$ echo vim # Assuming EDITOR was set

with Ctrl+x+e would become

1 echo vim # Assuming EDITOR was set
~
~
/tmp/sometmpbufferfile

Note that upon quitting vim, the contents of the vim buffer are executed on the command line.

These features become very useful for me when I want to do multi-line commands in bash such as for loops or programs requiring here statements, and provides an interesting way to save a bit of command-line history to file for later use.

So to answer the original question, you could also write,

$ This is an example

and then hit Ctrl+x+e to load it up in vim. Also you could have,

 $ $(cat /etc/hosts)

and do Meta(Alt/Opt/Esc)+Ctrl+e then Ctrl+x+e, which would put all of the hosts file on one line and load it up in vim (probably not the best use of these features--however, the usefulness of these methods can be extrapolated from the few examples discussed here).

Note that I assume that your readline is set to emacs mode. If your readline is set to vim mode you can easily discover the relevant bindings by using the command:

bind -p

and searching for edit-and-execute-command or shell-expand-line, which were respectively associated with the bindings Ctrl+x+e and Meta(Alt/Opt/Esc)+Ctrl+e.

  • You can tell bash to use vi key bindings instead of emacs. Use set -o vi to turn it on. Then you can just use the v mapping in normal mode to edit the current command in your editor. – Quincy Bowers Feb 12 '15 at 19:19
  • 1
    For sure this is a great trick to edit the command line using vi but there are at least two problems using this method to read text from stdin: 1. shell-expand-line remove newlines from the expanded text and 2. edit-and-execute-command try to execute the command written in the buffer, whatever it is saved or not, when you quit vi. – toro2k Feb 12 '15 at 19:35
  • Woah, this is awesome. I learn a new thing about readline every day, it seems... – Doorknob Feb 12 '15 at 21:48
2

In bash I've found it useful to use process substitution using the <(command) syntax, in example:

vim <(echo This is example.)
vim <(cat /etc/hosts)

See also:

  • 4
    Note this will won't work in all shells. I think it will only work in bash and zsh (and not sh, ksh, dash, fish, csh, tcsh, etc.) – Martin Tournoij Feb 12 '15 at 17:17
  • @Carpetsmoker Should work in ksh88 and above, I think, but yes, process substitution is not POSIX. – muru Feb 12 '15 at 18:41
  • 4
    And pay attention to not trick yourself! When you start Vim this way it opens a buffer for a file like /proc/PID/fd/FD. If you write the buffer and quit, Vim doesn't complain, but the file you have written to will be removed by the OS. Using - as the file name the opened buffer have no file associated with it so if you try to quit without (as long you don't use a bang command or similar) saving Vim will warn you. – toro2k Feb 12 '15 at 19:48
  • 1
    This is nice because it generalizes well to vimdiff <(echo foo) <(echo bar). – wchargin Feb 20 '15 at 15:42
  • @toro2k To follow up, it looks like using :next and :prev re-reads the stream and gets nothing. It's also worth mentioning that the processes are not parallel to one another - e.g. cat <(sleep 3; echo a) <(echo b) prints in order - and while cat interleaves writes and reads, vim waits on the file to "finish reading" before displaying all but the outer frame. – John P Dec 31 '17 at 13:57
0

If using a pipeline to a new Vim is not a requirement, you can use Vim's ability to pull in the output of commands into the current buffer, coupled with having a non-file backed buffer (as with :new or editing a non-existent file)

:read!cat /etc/hosts in command-mode will place the output into your current buffer below the current cursor position.

Apart from having to delete the empty first line that remains when this is done on an empty buffer, this works well and is especially convenient if Vim is already running.

  • 1
    How does this answer the question? – muru Feb 19 '15 at 8:39
  • It takes the output of the command and puts it into vim. – ewatt Feb 19 '15 at 8:43

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.