DEV Community

loading...

Type less and save time with Vim's global command!

iggredible profile image Igor Irianto Originally published at irian.to Updated on ・4 min read

Vim's global (:h :g for more info) command is a useful tool to quickly perform Ex command within the file you're currently editing (some common example of Ex commands are: d (delete), t (copy), s (substitute), m (move), etc). Used properly, it can save you a lot of time typing.

g follows the syntax:

:[range]g[lobal]/{pattern}/[cmd]
Enter fullscreen mode Exit fullscreen mode

Here I will cover basic, slightly more advanced, and advanced use cases. If this is your first time using g, you don't have to follow the advanced one yet, feel free to come back later after getting more experience with it. Learning Vim takes a lot of muscle memories. I am still learning new something new about Vim all the time! 🤓

When to use it?

Anytime you find yourself repeating the same Ex command in one file, you should start thinking, "How can I do this in one stroke with :g?"

Basic use cases

Let's start with basic use cases, going to more sophisticated ones.

Suppose you have a file with many "const" and you need to delete them all:

const hello = "world";
const foo = "bar";
const baz = "qux";
// and many more const...
Enter fullscreen mode Exit fullscreen mode

Run :g/const/d and they are gone!

What just happened?

We gave g a pattern: "const" string. It found all lines (g is line-based) that matches the pattern. It performed d (deletion) to those matches.

g by default will perform p (print) if no command is passed. Try it: :g/const/.

It also accepts ranges. Let's say you want to get rid of all empty lines between lines 10 and 20. You can do this by:

:10,20g/^$/d
Enter fullscreen mode Exit fullscreen mode

Note: ^$ is a regex pattern for blank lines.

Slightly more advanced use cases

Let's move on to more fancy use cases.

Suppose you have the following and want to reverse the line order:

const one = 1;
const two = 2;
const three = 3;
const four = 4;
Enter fullscreen mode Exit fullscreen mode

To do that with :g, you can do:

:global/^/m 0
Enter fullscreen mode Exit fullscreen mode

We'd get:

const four = 4;
const three = 3;
const two = 2;
const one = 1;
Enter fullscreen mode Exit fullscreen mode

Pretty cool, but how did it work?

m 0 moves (see :h :m for details) a line into target line number (line 0). If you want to do it yourself manually, you can go to line 1, run :m 0, then go to next line, run :m 0, then next line, run :m 0, etc. You'll notice the lines are gradually being put on top of the latest one. The difference is, g does it for you in one move. (btw, ^ is a pattern for beginning of line; here it selects all lines in a file).

Pretty cool! 😎

You can combine g with substitute (s):

good, bad, ugly
you're so good it's bad
nothing bad here
Enter fullscreen mode Exit fullscreen mode

If we want to substitute all "bad"s into "nice", but only on the lines that contain "good", we can do:

:g/good/s/bad/nice/g
Enter fullscreen mode Exit fullscreen mode

We'd get:

good, nice, ugly
you're so good it's nice
nothing bad here
Enter fullscreen mode Exit fullscreen mode

Advanced use cases

g can be used with macros. The syntax is :

:g/keyword/norm! @q
Enter fullscreen mode Exit fullscreen mode

Let's say we have a the following:

import lib1
import lib2

const something = 'else';

import lib3
// ...and many more imports
Enter fullscreen mode Exit fullscreen mode

Our tasks are:

  1. wrap all libs with {}
  2. capitalize the l in lib

We can create macro to do our tasks. But we don't want to execute our macro on lines not containing import. Does that mean we have to apply our macros individually on each line we want to do it on?

Well, with g, we can select to apply our macros only to lines containing "import"! Imagine the time saving if you have to do it on 100+ lines!

Assuming we have vim-surround installed (for quick brackets wrap), here's how we can do it!

  • Record a macro to do tasks 1 and 2. With our cursor on "i" in import lib1, run:
qq0w~ysiw{q
// qq = record macro in q register
// 0 = go to beginning of line
// w = jump one word
// ~ = capitalize letter under cursor
// ysiw{ = vim-surround: add {} around lib1
// q = exit recording
Enter fullscreen mode Exit fullscreen mode
  • Undo the changes so our line is back to our original state: import lib1
  • Now execute the macro on only lines containing "import" with :g!
:g/import/norm! @q
Enter fullscreen mode Exit fullscreen mode

And there you have it:

import { Lib1 }
import { Lib2 }

const something = 'else';

import { Lib3 }
// and more...
Enter fullscreen mode Exit fullscreen mode

g also accepts a different range. The syntax is:

:g/pattern1/, /pattern2/ {cmd}
Enter fullscreen mode Exit fullscreen mode

This applies the {cmd} only to "blocks" between pattern1 and pattern2 (inclusive).

A practical use case is, suppose we have the following:

const something = {
   c:  'x',
   b:  'x',
   a:  'x',
   d:  'x',
}

const else = {
   d: 'x',
   c: 'x',
   a: 'x',
   b: 'x',
}

const a = 'hello'
const b = 'foo'
const c = 'bar'

Enter fullscreen mode Exit fullscreen mode

And we want to sort only the keys inside something and else and nothing else.

If you do:

:g/\v\{/+1,/\v}/-1 sort
Enter fullscreen mode Exit fullscreen mode

Everything inside your objects are now sorted and everything else remains unsorted:

const something = {
   a:  'x',
   b:  'x',
   c:  'x',
   d:  'x',
}

const else = {
   a: 'x',
   b: 'x',
   c: 'x',
   d: 'x',
}

const c = 'bar'
const a = 'hello'
const b = 'foo'

Enter fullscreen mode Exit fullscreen mode

Which is exactly what we wanted.

Here's the breakdown:
:g/\v\{/+1,/\v}/-1 sort

  • \v - activates vim's very magic
  • \{ - selects { (escape special character)
  • +1 - means apply the range 1 line after the match
  • -1 - apply the range 1 line before the match
  • sort - vim's sorting method

And there you have it! Vim's global command. This is just the surface of what it can do. Have fun experimenting!

What other useful cases do you think you can use it for?

Thanks for reading. I started a twitter account to share daily vim tips. If you're interested, follow @learnvim! 😁

Discussion (8)

pic
Editor guide
Collapse
moopet profile image
Ben Sinclair

I use this in Javascript to get rid of console.log lines.

I think it's a great reason people should stick to one command per line rather than chaining them with semi-colons :)

Collapse
rgaiken profile image
rgaiken

Same. I like to search first to see where I wrote the console statements (and ensure that they aren't inline with something important), then do :g//d (if you leave the search blank it'll just use whatever is in your search buffer)

Collapse
iggredible profile image
Igor Irianto Author

That's right, vim repeats the last search if we leave pattern blank (//)! Good call!

Collapse
iggredible profile image
Igor Irianto Author

Oh, nice!! I console.log quite a lot and didn't think of doing that. Good suggestion!
So glad you shared this 👍

Collapse
doom4535 profile image
Aaron Covrig

I believe this line:
:g/good/s/bad/ugly/g

Should be replaced with:
:g/good/s/bad/nice/g

Collapse
iggredible profile image
Igor Irianto Author

Woops, good catch!! Just fixed it 😅

Collapse
storypixel profile image
Sam Wilson

this is the clearest explanation of :g that I've ever read

Collapse
iggredible profile image
Igor Irianto Author

Thank you! Really glad you find it helpful. I'll keep that in mind in my future articles! 👍