We sometimes need to filter a text file (denoted as file.txt in this post) using some external program in-place, e.g. pretty-formatting a compact json file using jq. By “filter in-place”, I mean to pass the text file to the external program as stdin, and overwrite the original file with the program’s stdout. A direct solution is:

tmp=$(mktemp tmp.XXXXXX) && jq < file.txt > $tmp && mv $tmp file.txt

Inspired by this post, I found a more concise way to implement the function:

vim -es -c '%!jq' -cx file.txt

Explanation:

  • vim -es starts vim in Ex mode (-e) silently (-s).
  • -c '%!jq' filters (!) the entire (%) buffer using jq.
  • -cx saves the buffer and exits (see vim-help for more about :x command).