Replace a regular expression within vim with an output produced by a console command with the expression as its argument?

let's say I have a file with the following content:

This is a _file_ which has some _special_ keywords, that I would _like_ to replace.

I can do a search and replace of the speical keywords with "%s/_*_/something", but I would like "something" to be an output of an external command. Is this possible in vim, or do I need to awk it?


Solution 1:

Yes, you can. See :help sub-replace-special; the \= allows you to replace with a Vim expression. And system() can execute an external command and return its output. See my trivial example with hostname. Note that I had to use substitute() to get rid of the trailing newline character(s) in the output.

:%s/_[^_]*_/\=substitute(system('hostname'),'\n','','g')/g

PS: I also corrected your regexp pattern to match your example.

Solution 2:

In Ingos answer, which helped me a lot, I don't see how to reference a subpattern of the match and use it as an argument to the shell command ("produced by a console command with the expression as its argument").

In my case I had log lines of the following form: [<unix timestamp>] <message>, i.e. [1406844000] foobar. I wanted to prepend them with the time in a human readable form.

The following vim command matches the timestamp (submatch 1) and the message (the rest, submatch 2) and prepends the time string from date command:

:% s/^\[\(\d\+\)\] \(.*\)$/\=substitute(system('date -d @'.submatch(1)),'\n', '', 'g').': ['.submatch(1).'] '.submatch(2)/

[1406844000] foobar gets Fr 1. Aug 00:00:00 CEST 2014: [1406844000] foobar.

HTH