Is there any chance to write the content of the current vim buffer to stdout?
I'd like to use vim to edit content that was passed via stdin - without the need of a temporary file to retrieve the modified content (on Linux/U开发者_运维技巧nix).
Is it possible that a plugin/script - that act on quit or save put the buffer content to stdout?
I think :w !tee
would work perfectly,
Since you use Linux/Unix, you might also be interested in trying out moreutils. It provides a command called vipe
, which reads from stdin
, lets you edit the text in $EDITOR
, and then prints the modified text to stdout
.
So make sure you set your editor to Vim:
export EDITOR=vim
And then you can try these examples:
cat /etc/fstab | vipe
cut -d' ' -f2 /etc/mtab | vipe | less
< /dev/null vipe
To print buffer to shell standard output, vim
needs to start in Ex mode, otherwise it'll open the "normal" way with its own window and clear any output buffers on quit.
Here is the simplest working example:
$ echo foo | vim -es '+%print' '+:q!' /dev/stdin
foo
The special file descriptor to standard input needs to be specified (/dev/stdin
) in order to prevent extra annoying messages.
And here are some string parsing examples:
$ echo This is example. | vim -es '+s/example/test/g' '+%print' '+:q!' /dev/stdin
This is test.
$ echo This is example. | vim - -es '+s/example/test/g' '+%print' '+:q!'
Vim: Reading from stdin...
This is test.
Here is a simple example using ex
which is equivalent to vi -e
:
ex -s +%p -cq /etc/hosts
Related:
- How to edit files non-interactively (e.g. in pipeline)? at Vim SE
- Pipe Vim buffer to stdout at stackoverflow
Reading from stdin:
echo "hey" | vim -
When you :w
you'd still have to give it a filename.
Programs that use vim
as their EDITOR
, like crontab -e
pass it a filename so that user can just :x
and not worry about filenames.
EDIT
You could also do something like this:
mkfifo /tmp/some_pipe
echo "hey" > /tmp/some_pipe ; cat /tmp/some_pipe
And from another process (or terminal)
vim /tmp/some_pipe
Beware that writing to a pipe will block until something reads from it, and reading will block untill something writes to it, so it might be safer to use regular files.
Using :print
will write to stdout, particularly if vim is run with both the -E
and -s
options, which cause it to run noninteractively and silently. See :h -E
and :h -s-ex
:
The output of these commands is displayed (to stdout):
:print
:list
:number
:set to display option values."
Use :%print
to print the whole current buffer.
vim can be used in pipes as full-featured filter with explicit names for stdin and stdout as in following example:
echo xxx |
vim \
-esnN -i NONE \
+'1 s /x/y/g | 1 s /^/Hallo / | x! /dev/stdout' \
/dev/stdin |
cat -n
Abbreviating /dev/stdin
with -
won't work, even not with -v
flag.
Try something like:
{ FROMCMD | vim - 8>&1 >&9 | tac | tac | TOCMD; } 9>&1
and use ':w !cat >&8' when you are finished editing
'tac | tac' ensures that TOCMD doesn't receive any data until you quite vim, this is only useful if TOCMD writes to the terminal so that it doesn't make a mess while vim is still running.
Notice that running 'less' as your TOCMD (or any other program that do some terminal manipulation) is not going to work as expected because even if you delay the data, the processes still start "at the same time" and may access the terminal at the same time.
This post gave me an idea: copying the buffer/or selection to clipboard:
Install
xclip
(any linux distribuition package manager should have it.)Do this vim command:
:w !xclip
If you want to copy only some lines, select tem first with (normal mode) V
, then issue the command above.
You can also use pipe.vim. It does use a temporary file, but at least you don't have to worry about it in your own script.
To the second part of your question, you use the -s
command line option with vim to remap :w
to something else (like :w !tee
).
You can use the ex-mode (p)rint command to print any set of lines you want to stdout.
print all lines:
:1,$p
Also prints all lines (% is a shorthand for the range 1,$)
:%p
print lines 4-10:
:4,10p
print next line containing FOO
/FOO/ p
print all lines containing FOO
g/FOO/ p
What helped resolve matters for me is adding
setenv SHELL /bin/bash
exec bash -l
to .bashrc, otherwise vim can launch the wrong shell. Also, a script called save, which encrypts stdin and saves the result to $1, so the command in vim becomes :w !save afilename
.
精彩评论