I know in vim I can use :global to execute commands on the matching lines.

But I'm wondering if it's possible to execute those commands on every matching pattern, not just lines, consider following example:

aaa bbb
aaa ccc aaa ddd ww

I want to perform action: normal wdw on every matching aaa, so I expect the result to be:

aaa aaa ww

But with global, it will only do the action once on the 2nd line.

4 Answers 4


You might be interested by this question: Run a command on every match of a search (not on the line). The answer suggests the use of sub-replace-expression but this is more adapted when the changes are localized to the matches, and requires you to define a function.

However if the command changes often you would be better off using macros.

Here is one way to do it on your snippet, with the explanation:

  • gg Go to the top
  • /aaa<CR> Search to go on the first match
  • qq Start recording a macro into the q register
  • wdw Execute your commands, be careful where your cursor lands
  • Nn Needed to put the cursor on the next match every time in this case
  • q Stop recording
  • 2@q Play two times, or use a recursive macro but mind your &wrapscan as B Layer explained
  • 1
    Now we don't necessarily have to write functions: we can use lambdas as well: see for instance: %s/aaa/\={ s -> toupper(s)}(submatch(0))/g Commented Sep 3, 2017 at 12:09
  • Nice indeed! But I can't figure out how to alter the text around the match, e.g. deleting the next word (wdw). Is this possible with the original search pattern?
    – LEI
    Commented Sep 3, 2017 at 12:15
  • Sorry. After giving more thoughts into it, lambda are pointless here as they return an expression. They are not full-fledged functions. toupper(submatch(0)) is more than enough in my example. My mistake. Commented Sep 3, 2017 at 13:58

There's nothing like it mentioned anywhere in repeat.txt (:h repeating) so one can probably conclude that there's no native support for it.

If you're running this on the whole file a recursive macro is a viable approach. Assuming we'll store it in register q the macro is nwdwN@q. Breaking it down...

  • n - search for the pattern ('aaa' in the question's example)
  • wdw - the base command to be repeated
  • N - search backwards for the pattern (taking us to same position as the initial n)
  • @q - rinse and repeat (this self-referential bit is the "recursive" part)

The following commands will demonstrate how things work.

  1. :let @/ = 'aaa' : Just as if we'd previously done a search using /aaa.
  2. :let @q = 'nwdwN@q' : Load the macro into register q
  3. gg : Go to the beginning of the file.
  4. @q : Run the macro.

IMPORTANT: If you have Vim configured to wrap around the end of your file when searching make sure to disable this feature first using :set nowrapscan. Afterwards, run :set wrapscan if you wish to re-enable the setting.

  • 1
    This is genius!
    – Blasco
    Commented Oct 19, 2019 at 12:30
  • 2
    @Blasco Oh, stop, you're making me blush. ;) Recursive macros are fun. Don't come up too often in real world scenarios but are mandatory if you (vim) golf.
    – B Layer
    Commented Nov 3, 2019 at 21:31
  • @DBenKnoble I think the recent edit is yours. If so, thanks for fixing the typo. I'm not sure, though, what you mean by this: "toggling wrapscan with :set wrapscan! is a mistake because the actual state of the option is hidden". set wrapscan! works just fine...it toggles that setting off then on. You're not experiencing same?
    – B Layer
    Commented May 11, 2021 at 16:37

This is job for :substitute


after the pattern (\zs), I match spaces (\s\+) followed by any number of non spaces (\S\+).

If you really want dw and not dW, you'll prefer \(\k\@!.\)\+\k\+ instead of \s\+\S\+

  • 1
    My first inclination was to suggest substitute, too, but the problem is you need to figure out a new pattern any time you change the command. With macro approach you can just drop in different normal mode commands (as long as they operate between patterns). For simply solving wdw, though, this is the most straightforward way.
    – B Layer
    Commented Sep 3, 2017 at 12:42
  • Typo? \S\+\s\+ at end of last sentence doesn't match what you have in the substitute command: \s\+\S\+.
    – B Layer
    Commented Sep 3, 2017 at 12:57
  • @BLayer, if the command was more complex, I may not have used :s. here, it's about deleting something. The movement also is not that complex. it's a movement full of side effects. For instance, in aaa, bbb, w will stop at the first coma. That's why I usually prefer regexes. BTW, thanks for noticing the typo. Commented Sep 3, 2017 at 13:55
  • Sure. I was going more by the subject, "execute command on every matching pattern", rather than the particular example but neither way of looking at it is more valid than the other.
    – B Layer
    Commented Sep 3, 2017 at 15:14

If you're using neovim and looking for a ergonomically friendly solution, I wrote a plugin specifically to address this issue after asking the same question myself.


With this plugin you could call:

:lua require('command-pat').OperateOnPattern()

Which will prompt you for a pattern and normal command. It works great on your given example.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.