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}
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?
- 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". - Second,
d
is executed against each matching line.
So if you want to delete all lines containing equal sign (=
), you can do:
:g/=/d
Inverse match
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"
.
Range
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.- 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
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
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
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
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 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
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.
move
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 buffer
put
Put 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 "
.
copy
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
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 macro
With macro q
ready, target the remaining "const"
and execute it on each line:
:g/const/normal @q
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
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\[/
- 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
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:
- Our
g
command pattern is[
, the array opening. - We execute command,
sort
, against each pattern. - The command has its own range, starting at the line after
[
match, ending at a line before]
. - 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:
- When you are working on repetitive task, is there a better/faster/programmatic way to do it? Chances are , there probably is.
- Read Vim
:help
, search and ask question online. - 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!