I can catch the output of running a system command via system() or systemlist(), but that actually gives me the result of stdout and stderr combined. As I am only interested in stdout (and may use stderr for other purposes), this isn't useful for me.

How can I separate the output of a system command between stdout and stderr?

  • You're mixing up the in / out / err names quite a bit (but I think I understand what you mean). Please do some proofreading and correct the references to stdin. Nov 22, 2019 at 12:01
  • @IngoKarkat Sorry, you are right, of course. I have fixed the question.
    – radlan
    Nov 22, 2019 at 14:10
  • 1
    use job_start
    – Mass
    Nov 27, 2019 at 2:26

3 Answers 3


Vim's system() indeed captures both standard out and standard error by default. If you just want one of those, just use the normal shell means to redirect the other to the null device.

For example, ignore stderr (2>) with Bash:

:echo system('grep root /etc/passwd /doesnotexist 2>/dev/null')

On Windows, you'd use 2>NUL instead.

Alternatively, you could (temporarily) modify the 'shellredir' setting; e.g. by dropping the 2>&1 from it to ignore stderr. (Thanks @ChristianBrabandt for the tip!)

separate stdout and stderr

If you need both (but separately), that's a bit tricky. You could:

  • redirect one / both into a temp file and read that via readfile(), or via another system('cat /tmpfile')
  • invoke the command twice, ignoring first stdout and then stderr
  • add prefixes (via sed) to one / both (possible with fancy piping and redirections), read all in one fell swoop, and separate inside Vim
  • 2
    Urgh, that's ugly. Being dependend on the operating system and additionally on the shell doesn't sound nice. The alternatives to separate stdout/stderr for using both also isn't funny, but I think your first approach for is doable without too much effort and still usable. What I dislike even more is the system dependency… As this seems to be the only way to achieve this, I accept your answer. Thank you very much!
    – radlan
    Nov 22, 2019 at 14:17
  • No, it only caputes stderr, if the shellredir option contains 2>%1 and this depends on the shell option. So simply setting :set srr=> should fix capturing the error Nov 22, 2019 at 16:18
  • Well, external commands naturally depend on the environment. In practice, most Unix/Linux shells are very similar (unless you're using an exotic one), and if you use Cygwin or WSL on Windows, you could even get away with a single implementation. Nov 22, 2019 at 18:25

The separation can be done using jobs.


job_start('grep root /etc/passwd /doesnotexist', {
  out_cb: On_stdout,
  err_cb: On_stderr,

def On_stdout(ch: channel, msg: string)
  # do something with msg

def On_stderr(ch: channel, msg: string)
  # do something with msg
  • Thank you for the example. But there is no need to use vim9script for it. Regular vimscript would do as well and would be way more compatible.
    – radlan
    Jul 13, 2022 at 18:32
  • In my opinion, it is not a bad thing to start using vim9 script more often given its many improvements over legacy vimscript.
    – r_31415
    Sep 4, 2022 at 0:59
:h r! -- [range]r[ead] !{cmd}

looks like a possible alternative to system() to insert its standard output below the cursor or the specified line.

It says shellredir is used to save the output of the command, which can be set to include stderr or not as @IngoKarat mentioned.

:help set-default to put it back.

A similar question and answer: read from external command captures stderr as well.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.