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

How do I populate the quickfix list from the output of an external shell command?

Answer

:cexpr system('grep -rn TODO .')

Explanation

The :cexpr command evaluates an expression and parses the result as quickfix entries using the current errorformat. Combined with system(), this lets you run any shell command and jump directly to matching locations in Vim. This is a powerful alternative to :make or :vimgrep when you want to leverage fast external tools like grep, rg, or custom linters.

How it works

  • :cexpr — sets the quickfix list from an expression
  • system('grep -rn TODO .') — runs grep recursively with line numbers, capturing its output as a string
  • Vim parses each line of output using errorformat (the default %f:%l:%m format works with grep -rn output)
  • After running, use :copen to view the quickfix list and navigate results

Example

Running :cexpr system('grep -rn TODO .') in a project might produce a quickfix list like:

./src/main.c|12| // TODO: refactor this function
./src/utils.c|45| // TODO: add error handling
./README.md|8| - TODO: update installation docs

You can then press <CR> on any entry to jump to that file and line.

Tips

  • Use :caddexpr instead to append results to the existing quickfix list without replacing it
  • For ripgrep users: :cexpr system('rg --vimgrep TODO') works out of the box since --vimgrep outputs in a format Vim understands
  • Set a custom errorformat before :cexpr if your tool's output format differs from the default
  • Combine with :cdo to perform batch operations on all matches: :cdo s/TODO/DONE/g | update

Next

How do I ignore whitespace changes when using Vim's diff mode?