DEV Community

Igor Irianto
Igor Irianto

Posted on • Edited on

Discovering Vim Global Command

Follow @learnvim for more Vim tips and tricks!

Vim's global command (:h :global) can be used to run Ex command in the buffer, allowing you to make edits instantly. Knowing how to use global command can save you a lot of time from doing repetitive tasks.

If Vim is your text editor, or if you are just checking out Vim, this article will show you things you can do with global command.

I wrote an article on global command in 2019. Between that time and now, I have learned new things (even now, I think I am barely scratching the surface of the command's real power).

Overview

This is the basic overview of g. Feel free to skip ahead if you already know it.

Basic Syntax

According to :h :global, the syntax looks like:

:[range]global/{pattern}/{command}
Enter fullscreen mode Exit fullscreen mode

Let's break it apart, one by one. In this section, I will use the command d for demo (I will cover more commands later). For more info, check out :h :delete

We will also use this test.js throughout this article, so you can code along:

const one = 1;
console.log("one: ", one);

const two = "two";
console.log("two: ", two);

const three = {num: 3};
console.log("three: ", three);
Enter fullscreen mode Exit fullscreen mode

To remove all lines containing "console", we do:

:g/console/d
Enter fullscreen mode Exit fullscreen mode

How does it work?

  1. First, g scans through the range. If not given any, by default it covers the entire buffer ((1,$)). In his case, it finds 3 matches: all lines containing "console".
  2. Second, d is executed against each matching line.

So if you want to delete all lines containing equal sign (=), you can do:

:g/=/d
Enter fullscreen mode Exit fullscreen mode

Inverse match

To effect non-matching lines instead of matching, instead of :g/pattern/{command}, you do either:

  1. :g!/{pattern}/{command}
  2. :v/{pattern}/{command}

If we run :v/console/d, it will delete all lines NOT containing "console".

Range

We can pass it a range. For example, if we do:

:1,5g/console/d
Enter fullscreen mode Exit fullscreen mode

It will find matches to "console" between lines 1 and 5.

Other range variations:

  1. . means current line. If you are on line one, and you want to pass a range from between current line to line 3, you can do :.,3g/console/d. It deletes all lines matching "console" between current line and 3.
  2. $ means end of current buffer/ file. If you do :4,$g/console/d, it deletes all matching lines between lines 4 and end of file.
  3. +n means n lines after. If we are on line 2 and we give :1,+2g/console/d, it will delete all matches between line 1 and 2 lines from current line.
  4. We can make range to go backwards. For example: :4,2g/console/d deletes every matching lines between lines 4 and 2.

Matching and non-matching

We can combine a matching pattern with non-matching pattern, for example:

:g/console/v/two/d
Enter fullscreen mode Exit fullscreen mode

This finds lines that contain "console", but not "two".

Delimiter

You don't have to use / as delimiter. You can use any single byte character that is not alphabetical (for example, you can use @,\,",|, but a-z won't work).

:g@console@d
Enter fullscreen mode Exit fullscreen mode

This is useful if your pattern contains many "/". For example, :g@https://mywebsite.com/stuff@d is easier to type than :g/https:\/\/mywebsite.com\/stuff/d.

Regex

I won't go deep into regex. But global command pattern accepts regular expression. For example, to find match inside double quotes:

:g/"[^"]*"/d
Enter fullscreen mode Exit fullscreen mode

Explanation:

  • " = literal quote
  • [^"]* = any character that is NOT a quote. This is a common pattern in regex.

Default command

We have been using d as our command. But if we don't specify any {cmd}, global command uses (p) by default.

For example:

:g/console
Enter fullscreen mode Exit fullscreen mode

One use case is if you have a list of TODO scattered across the file, you can use :g/TODO to display all TODOs.

Btw, cool fact: because the default command uses p if no {cmd} is given, This makes its syntax to look like:

:g/re/p
Enter fullscreen mode Exit fullscreen mode
  • g = global
  • re = regex pattern
  • p = print, the default command

Did you notice the spelling?

It spells "grep" - the same grep that lives in your command line.

This is not a coincidence. This command originally comes from Ed Editor, one of the first line text editors. And Grep got its name from Ed. Talk about family tree!

List of useful commands

Global command uses many commands from Ex editor. I will cover some of the useful ones.

delete

Again, the syntax for deletion is: :g/re/d.

Here is a useful command:

  • deleting blank lines :g/^$/d
    • /^$/ is regex for blank line (beginning of line, ^, followed by end of line $)
    • Even better, :g/^\s*$/d removes lines with blank spaces.

substitute

Substitution is another big one. If you are a Vim user, you probably have used :s extensively (:h substitute). Here you can combine s with global command.

To replace all "const" with "let", I can do:

:g/const/s/const/let/g
Enter fullscreen mode Exit fullscreen mode

This reads: "find all lines matching "const", then substitute the "const" with "let".

Some might find :g/const/s/const/let/g tedious to type. Why should I type const twice? Luckily, Vim realizes that and you can just do:

:g/const/s//let/g
Enter fullscreen mode Exit fullscreen mode

If you leave the first substitute argument blank, //, substitute will use the global command patten.

move

You can use m to move matches (for more info: :h :move). The syntax is simple:

:g/pattern/m destination
Enter fullscreen mode Exit fullscreen mode

To move all lines containing "console" to the end of file, do:

:g/console/m $
Enter fullscreen mode Exit fullscreen mode

Here's a useful one:

  • :g/^/m 0 reverses the entire buffer. ^ is the beginning of line, so it will match every line in the buffer

put

Put allows you to put text from register x (:h :put). Basic syntax:

:g/pattern/pu {register}
Enter fullscreen mode Exit fullscreen mode

For refresher on register, check out :h registers.

Let's say you have this stored in your register a: // Test comment. To put that line automatically after "console" text, do:

:g/console/pu a
Enter fullscreen mode Exit fullscreen mode

You don't have to always paste from register. You can make put to output your own text with:

:g/console/pu =\"//Test comment\"
Enter fullscreen mode Exit fullscreen mode

This will put the //Test comment after each console. Unfortunately, we have to escape ".

copy

Vim has Copy method (:h :copy). With g command, it works with t. Basic syntax:

:g/pattern/t {address}
Enter fullscreen mode Exit fullscreen mode

It copies all matching pattern to address.

One use case is, if you want to copy all "console" to the end of the buffer:

:g/console/t $
Enter fullscreen mode Exit fullscreen mode

normal

Normal (:h :normal) is not an Ex command. It allows you to execute Vim's normal mode command. Syntax is:

:g/pattern/normal {normal-mode-command}
Enter fullscreen mode Exit fullscreen mode

If you want to comment out all lines with "console". You can use Vim's global + normal with:

:g/console/normal I//
Enter fullscreen mode Exit fullscreen mode

Vim will find all lines containing "console" and perform I// (go to insert mode before first nonblank in the line, add //).

One of the power of Vim's normal command is that it can run anything normal mode can, including macros (:h :q).

If we want to change all const into let with macros, here is how:

First, create macro to change const to let. With cursor on top first line, first character:

qqciwlet<Esc>q
Enter fullscreen mode Exit fullscreen mode

Explanation:

  • qq = start macro on q register
  • ciw = change inner word (deletes "const" and go to insert mode)
  • let<Esc> = type "let", go to normal mode
  • q = stop macro

With macro q ready, target the remaining "const" and execute it on each line:

:g/const/normal @q
Enter fullscreen mode Exit fullscreen mode

sort

You can combine g with sort (:h :sort). Frankly, I find that sort is easier to use directly with visual mode. If you only have one or two things to sort, the easiest way is to go to visual mode, highlight them, and run :sort.

However, I have one use case that I use somewhat often and I want to mention it here.

For the demo, we will have to use a different text this time.

const someArr = [
  "i",
  "g",
  "h",
  "b",
  "f",
  "d",
  "e",
  "c",
  "a",
]

const someMoreArray = [
  "h",
  "b",
  "f",
  "d",
  "e",
  "c",
  "a"
]
// and more
Enter fullscreen mode Exit fullscreen mode

Let's say you have a huge file with hundreds of these arrays. You want the elements on each array sorted, but not the arrays themselves.

We can use global command to target only the elements of each array to perform sort on. Here is the command: :g /\v\[/ +1,/\v\]/-1 sort (I did something similar on my last article, but let me explain again):

This command consists of 3 parts:

:g /\v\[/ +1,/\v\]/-1 sort
  ^--1st ^--2nd      ^--3rd
Enter fullscreen mode Exit fullscreen mode

1st is our pattern. 2nd and 3rd are our command. Let me explain:

Recall our g command syntax:

:g/{pattern}/{command}
Enter fullscreen mode Exit fullscreen mode

Our pattern is:

/\v\[/
Enter fullscreen mode Exit fullscreen mode
  • It uses Vim's very magic (:h magic)
  • \[ finds match for [, the square bracket opening of our array.

Our command is:

+1,/\v\]/-1 sort
Enter fullscreen mode Exit fullscreen mode

This actually consists of two parts:

[range] {cmd}
Enter fullscreen mode Exit fullscreen mode

What I didn't tell you, is that we can also pass an additional range into our command.

Our command range is:

+1,/\v\]/-1
Enter fullscreen mode Exit fullscreen mode

Our command is:

sort
Enter fullscreen mode Exit fullscreen mode

This is what the command does:

  1. Our g command pattern is [, the array opening.
  2. We execute command, sort, against each pattern.
  3. The command has its own range, starting at the line after [ match, ending at a line before ].
  4. It performs sort within that range.

If your mind is baffled by the sort, don't worry. When I first learned this method, I stared at the screen for 10-15 minutes trying to comprehend it, unsuccessfully. Take your time, come back in a few days with fresh mind.

Tips for continuous learning

Learning Vim is a long-term commitment. Here are some tips to get better:

  1. When you are working on repetitive task, is there a better/faster/programmatic way to do it? Chances are , there probably is.
  2. Read Vim :help, search and ask question online.
  3. When you figure it out, at first it will be awkward and slow. Repeat it until you can do it with little/no thinking.

Happy coding!

Shameless disclaimer: if you enjoy this, there's a 98.39% (not scientifically proven) you will also enjoy my Vim Cookbook: Gourmet Vim. Check it out!

Top comments (6)

Collapse
 
scriptmunkee profile image
Ken Simeon

Thank you, Igor! I've learned a lot today. 👍🏽

Collapse
 
iggredible profile image
Igor Irianto

You're welcome.
Really encouraging knowing people benefitted from this 👍

Collapse
 
scriptmunkee profile image
Ken Simeon

Since I started readying your Vim articles my usage of Vim has massively improved. Thank you and please don't stop spreading your knowledge

I've been a daily user of Vim for all of my development and text editing needs, but never put in enough time to go beyond learning what I needed to complete a given task. Your write ups always provide me we more weapons in my Vim tool belt.

Thank you

Thread Thread
 
iggredible profile image
Igor Irianto

Definitely. I am really glad that it reaches at least one person. This comment makes it worth it.
Yup, there are more coming :).

Thread Thread
 
scriptmunkee profile image
Ken Simeon

I'm looking forward to your next post.

Cheers!

Collapse
 
_ajp_ profile image
AJP

Amazing. Thanks for some great tips.