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).
This is the basic overview of g
. Feel free to skip ahead if you already know it.
According to :h :global
, the syntax looks like:
:[range]global/{pattern}/{command}
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);
To remove all lines containing "console"
, we do:
:g/console/d
How does it work?
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".d
is executed against each matching line.So if you want to delete all lines containing equal sign (=
), you can do:
:g/=/d
To effect non-matching lines instead of matching, instead of :g/pattern/{command}
, you do either:
:g!/{pattern}/{command}
:v/{pattern}/{command}
If we run :v/console/d
, it will delete all lines NOT containing "console"
.
We can pass it a range. For example, if we do:
:1,5g/console/d
It will find matches to "console"
between lines 1 and 5.
Other range variations:
.
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.$
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.+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,2g/console/d
deletes every matching lines between lines 4 and 2.We can combine a matching pattern with non-matching pattern, for example:
:g/console/v/two/d
This finds lines that contain "console"
, but not "two"
.
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
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
.
I won't go deep into regex. But global command pattern accepts regular expression. For example, to find match inside double quotes:
:g/"[^"]*"/d
Explanation:
"
= literal quote[^"]*
= any character that is NOT a quote. This is a common pattern in regex.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
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
g
= globalre
= regex patternp
= print, the default commandDid 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!
Global command uses many commands from Ex editor. I will cover some of the useful ones.
Again, the syntax for deletion is: :g/re/d
.
Here is a useful command:
:g/^$/d
/^$/
is regex for blank line (beginning of line, ^
, followed by end of line $
):g/^\s*$/d
removes lines with blank spaces.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
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
If you leave the first substitute argument blank, //
, substitute will use the global command patten.
You can use m
to move matches (for more info: :h :move
). The syntax is simple:
:g/pattern/m destination
To move all lines containing "console"
to the end of file, do:
:g/console/m $
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 bufferPut allows you to put text from register x (:h :put
). Basic syntax:
:g/pattern/pu {register}
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
You don't have to always paste from register. You can make put
to output your own text with:
:g/console/pu =\"//Test comment\"
This will put the //Test comment
after each console. Unfortunately, we have to escape "
.
Vim has Copy method (:h :copy
). With g command, it works with t
. Basic syntax:
:g/pattern/t {address}
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 $
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}
If you want to comment out all lines with "console"
. You can use Vim's global + normal with:
:g/console/normal I//
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
Explanation:
qq
= start macro on q registerciw
= change inner word (deletes "const" and go to insert mode)let<Esc>
= type "let", go to normal modeq
= stop macroWith macro q
ready, target the remaining "const"
and execute it on each line:
:g/const/normal @q
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
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
1st is our pattern. 2nd and 3rd are our command. Let me explain:
Recall our g
command syntax:
:g/{pattern}/{command}
Our pattern is:
/\v\[/
:h magic
)\[
finds match for [
, the square bracket opening of our array.Our command is:
+1,/\v\]/-1 sort
This actually consists of two parts:
[range] {cmd}
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
Our command is:
sort
This is what the command does:
g
command pattern is [
, the array opening.sort
, against each pattern.[
match, ending at a line before ]
.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.
Learning Vim is a long-term commitment. Here are some tips to get better:
:help
, search and ask question online. 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!