There are 3 closely related vim commands that let you call an external program:
:[range]!{filter-cmd} {arg}
(ex-command, :help :range!
)
:[range]write !{cmd}
(ex-command, :help :w_c
)
system({expr}, {arg})
(vimscript function, :help system()
)
(I'm including !
and :!cmd
as part of 1.)
From my view, there are three important distinctions:
[range]
is sent to stdin in, stdout replaces [range]
[range]
is sent to stdin, stdout is ignoredsystem()
, so stdout can be saved to a variable as :let @a = system(..)
Is there really no way to send the current buffer or current line as stdin to an external command AND have unfettered access to stdout?
If you want to write, e.g., a complicated movement command that requires parsing of the line/buffer (parsing which would be better off not written in vimscript), this seems very surprising.
(Trying to send stuff through {arg}
would be crazy for a couple reasons: 1. character length limits, 2. you'd have to write a shell escaping function from within vimscript*)
Here is the only other related question I could find. It sends a string variable as shell arguments to (unix) 'echo', which then sends it as stdin to your program: Can I pass a string as stdin to a system call from vim?
*If the vim function shellescape()
does what you want, great, but on Windows it isn't even remotely robust for protecting input from cmd.exe
and from CommandLineToArgvW
. In fact, on Windows vim sends any single shell string through cmd.exe
twice.
OK, I was erring about one very important detail: the second argument to system({expr},{input})
isn't treated as shell input, it is sent as stdin. So you would do something like:
:let stdin = join(getline(1,'$'), "\n")
:let a = system('C:/main.exe',stdin)
Almost all examples of system(..)
use and warn about shell escaping, but that is for the {expr}
argument (and this escaping is a much smaller problem if {expr}
is not a dynamic string).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With