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