Patryk
Patryk

Reputation: 24092

Run a shell command on every line matching pattern

I'd like to run jq on every line matching a specific pattern, I tried:

:g/^\s\+{/!jq .

where ^\s+{ is my pattern but it doesn't work. I get a lot of errors like this:

...

:!jq .
[No write since last change]

:!jq .
[No write since last change]

...

I can use something like:

 g/^\s\+{/p

which will work and will print all of the lines matching my pattern.

Any suggestions?

Upvotes: 1

Views: 307

Answers (1)

Ingo Karkat
Ingo Karkat

Reputation: 172510

If I understand you correctly, you have a file with multiple JSON documents, each one concatenated on a single line, and you now want to pretty-print each such document into indented, multi-line ones with jq .

What you do with :g/^\s\+{/ is locating lines with JSON documents, and then executing the command on it. The problem is in the :!jq . The way I've written it, you may already recognize that this is :help :!cmd, whereas you've intended to filter the current line (a JSON document spread over multiple subsequent lines would also work, but require a range). The filtering command is subtly different; :help :range!.

So, with :!jq ., Vim just launches the external jq with the . argument, but it doesn't pass anything from the buffer to it. That's why jq is just sitting there and waiting for input until you abort it (e.g. with <C-c>).

The :.!jq . command instead passes the current line :. as a range to the jq command, and then replaces the original line with the command's output, just as you want. Adding that single . fixes your command:

:g/^\s\+{/.!jq .

Upvotes: 4

Related Questions