:!{cmd}
sends {cmd}
to the shell which executes it and shows its output on the screen.
:{range}!{filter}
sends the lines from the current buffer inside {range}
as the input of the {filter}
program and replaces them with its output.
In your example, :%!jq
:
%
is the range, which means: all the lines of the current buffer
It could also be written 1,$
(from the first line to the last one)
jq
is the filter program
Here's a page describing the various ways of writing a range.
And on this page, you can find other usage examples of a filter program :
:%! xxd [-r]
:%! column -t
:%! sort
The first one replaces a binary file with a hex dump (or the reverse with the -r
flag).
The second one formats data from the file into a table.
The third one sorts lines according to the first characters.
You can test the third one, with this simple file:
3 !
2 world
1 hello
After typing :%! sort
, the buffer is replaced with:
1 hello
2 world
3 !
If you had typed :!sort %
, the output would have been displayed on the screen but would not have replaced the buffer.
Note that the %
sign doesn't mean the same thing depending on where it is placed:
Before the bang (and more generally before most Ex commands), it's
interpreted as a range (same as 1,$
) which tells vim which lines
must be filtered.
After the bang (and more generally after most Ex commands), it's expanded as the name of the current file before the full command is sent to the shell.
For more information, see:
:help filter
:help range