vimtricks.wiki Concise Vim tricks, one at a time.

How do I run a shell command from Vimscript and capture its output as a list of individual lines?

Answer

systemlist()

Explanation

systemlist({cmd}) runs a shell command and returns the output as a list of strings, one per line — unlike system() which returns everything as a single string. This makes it easy to loop over output, filter it, or pass it directly to functions that expect lists.

How it works

  • system('cmd') — returns output as one string: "line1\nline2\n"
  • systemlist('cmd') — returns output split by newlines: ['line1', 'line2']
  • Trailing newlines are trimmed from each element automatically
let files = systemlist('git diff --name-only')
for f in files
  echo f
endfor

Example

Populate the quickfix list with output from a custom linter:

let output = systemlist('mycheck ' . expand('%'))
let qflist = map(output, '{"text": v:val}')
call setqflist(qflist)
copen

Or insert all files in a directory as a numbered list:

:put =systemlist('ls -1')

Tips

  • Use filter(systemlist('cmd'), 'v:val =~ "pattern"') to keep only matching lines
  • map(systemlist('cmd'), 'trim(v:val)') to strip leading/trailing whitespace from each line
  • Pass shell arguments safely with shellescape(): systemlist('grep -r ' . shellescape(word) . ' .')
  • In Neovim Lua, vim.fn.systemlist('cmd') works identically and returns a Lua table

Next

How do I read from and write to files directly in Vimscript without shelling out to external commands?