Chaining global commands
Global commands can be chained in Vim. That means the Ex command you pass to a :global invocation can be another :global invocation. This sounds a bit crazy, but think about the following examples:
- :g/test/g/run — prints all of the lines matching both test and run
- :g/foo/v/bar — prints all lines containing foo, but not bar
- :g/foo/v/bar/g/baz — prints all lines containing foo and baz, but not bar
To give you some ideas, I’ve used this in the past to:
- delete all debugging print statements that I’ve not explicitly marked with the string KEEPME (hint: :g/print/v/KEEPME/d)
- list all of the type definitions in a file that don’t contain GET in their name (hint: :g/^type/v/GET/)
- slowly whittle down what I’m grepping for in a file by chaining more global commands — I think this is a bit easier to cognitively manage than writing a more complex regex
The only limitation with using the global command recursively is that you can only specify a range for the first invocation of :global. As in, you can’t do this:
:g/foo/-10,+10g/bar/d
Thankfully the situations where you’d ever need this are extremely rare.
Let’s give this a try in the editor. The chain reads left to right: :g/foo selects the lines containing foo, v/bar filters that selection down to the ones without bar, and d deletes what’s left. Work through the checklist below to run it.