Vim Tips Wiki
m (Power of moved to Power of g: Old title was 'Power of :g' (but wiki doesn't like colon); have kept the quirky title because it's nice)
(Undo revision 37152 by 67.180.48.92 (talk) What is wrong?)
(29 intermediate revisions by 15 users not shown)
Line 1: Line 1:
  +
{{TipImported
{{review}}
 
{{Tip
 
 
|id=227
 
|id=227
  +
|previous=225
|title=Power of
 
  +
|next=228
|created=March 24, 2002 3:15
 
  +
|created=2002
 
|complexity=intermediate
 
|complexity=intermediate
 
|author=Arun Easi
 
|author=Arun Easi
|version=5.7
+
|version=6.0
 
|rating=900/308
 
|rating=900/308
  +
|category1=Searching
|text=
 
  +
|category2=
:g is something very old and which is very powerful. I just wanted to illustrate the use of it
 
 
with some examples. Hope, it will be useful for someone.
 
 
 
 
Brief explanation for ":g"
 
 
-------------------------
 
 
Syntax is:
 
 
:[range]:g/<pattern>/[cmd]
 
 
You can think the working as, for the range (default whole file), execute
 
 
the colon command(ex) "cmd" for the lines matching <pattern>. Also, for all
 
 
lines that matched the pattern, "." is set to that particular line (for
 
 
certain commands if line is not specified "." (current line) is assumed).
 
 
 
 
Some examples
 
 
-------------
 
 
Display context (5 lines) for all occurences of a pattern
 
 
:g/<pattern>/z#.5
 
 
:g/<pattern>/z#.5|echo "=========="
 
 
<< same as first, but with some beautification >>
 
 
Delete all lines matching a pattern
 
 
:g/<pattern>/d
 
 
Delete all blank lines (just an example for above)
 
 
:g/^\s*$/d
 
 
Double space the file
 
 
:g/^/pu =\"\n\"
 
 
:g/^/pu _
 
 
<< the above one also works >>
 
 
Copy all lines matching a pattern to end of file
 
 
:g/<pattern>/t$
 
 
Yank all lines matching a pattern to register 'a'
 
 
0"ay0:g/<pattern>/y A
 
 
Increment the number items from current line to end-of-document by one
 
 
:.,$g/^\d/exe "normal! \<c-a>"
 
 
Comment (C) lines containing "DEBUG" statements
 
 
g/^\s*DEBUG/exe "norm! I/* \<Esc>A */\<Esc>"
 
 
A Reverse lookup for records
 
 
(eg: An address book, with Name on start-of-line and fields after a space)
 
 
:g/<patern>?^\w?p "if only name is interested
 
 
:g/<patern>/ka|?^\w?p|'ap "if name and the lookup-line is interested
 
 
:g/<patern>/?^\w?|+,/^[^ ]/-1p "if entire record is interested
 
 
Reverse a file (just to show the power of 'g')
 
 
:g/^/m0
 
 
 
 
Foot note 1: use :v to negate the search pattern
 
 
Foot note 2: Some explanation of commonly used commands with :g
 
 
:2,8co15 => Copy lines 2 through 8 after line 15
 
 
:4,15t$ => Copy linesa 4 through 15 towards end of document (t == co)
 
 
:-t$ => Copy previous line to end of document
 
 
:m0 => Move current line to the top of the document
 
 
:.,+3m$-1 => Move current line through cur-line+3 to the last but one line
 
 
of the document
 
 
Foot note 3: Commands used with :g are ex commands, so a help search should
 
 
be,
 
 
:help :<help-topic>
 
 
eg. :help :k
 
 
 
 
}}
 
}}
  +
The global command <code>:g</code> is very useful. Here are some examples showing the power of <code>:g</code>.
   
  +
==Brief explanation of <code>:g</code>==
== Comments ==
 
  +
<pre>
Thanx Karma for extending my g// knowledge
 
  +
:[range]g/<pattern>/cmd
  +
</pre>
   
  +
This will act on the specified ''[range]'' (default whole file), by executing the Ex command ''cmd'' (An Ex command is one starting with a colon (':')) for each line matching ''<pattern>''. Before executing ''cmd'', "." is set to the current line.
Here's a very useful g// for day to day use
 
   
  +
==Examples==
:'a,'bg/pattern/s/pattern2/string3/gi
 
  +
Display context (5 lines) for all occurrences of a pattern.
  +
<pre>
  +
:g/<pattern>/z#.5
  +
" Same, but with some beautification.
  +
:g/<pattern>/z#.5|echo "=========="
  +
</pre>
   
  +
Delete all lines matching a pattern.
zzapper
 
  +
<pre>
  +
:g/<pattern>/d
  +
</pre>
   
  +
Delete all lines that do '''not''' match a pattern.
david--AT--tvis.co.uk
 
  +
<pre>
, March 28, 2002 7:10
 
  +
:g!/<pattern>/d
----
 
  +
</pre>
g WITH CONFIRM c
 
   
  +
Delete all blank lines (<code>^</code> is start of line; <code>\s*</code> is zero or more whitespace characters; <code>$</code> is end of line)
Here's something very curious:
 
  +
<pre>
  +
:g/^\s*$/d
  +
</pre>
   
  +
Double space the file (<code>^</code> is start of line which matches each line).
:%s/foo/bar/gc
 
  +
<pre>
is of course a substitution effective for the entire file
 
  +
:g/^/pu =\"\n\"
with confirm on each occurrence of "foo"
 
  +
" Alternative (:put inserts nothing from the blackhole register)
with the option of quitting at any point.
 
  +
:g/^/pu _
  +
</pre>
   
  +
Copy all lines matching a pattern to end of file.
However, using something similar,
 
  +
<pre>
  +
:g/<pattern>/t$
  +
</pre>
   
  +
Move all lines matching a pattern to end of file.
:g/foo/s//bar/gc
 
  +
<pre>
using the global g to effect the entire file --
 
  +
:g/<pattern>/m$
does NOT allow quitting at any point
 
  +
</pre>
(even with the use of &lt;ESC&gt;).
 
   
  +
Copy all lines matching a pattern to register 'a'.
If there are hundreds of "foo" -- it's an important fine point...
 
  +
<pre>
  +
qaq:g/<pattern>/y A
  +
</pre>
  +
:''Explanation'' <code>qaq</code> is a trick to clear register <code>a</code> (<code>qa</code> starts recording a macro to register <code>a</code>, then <code>q</code> stops recording, leaving <code>a</code> empty). <code>y A</code> is an Ex command ({{help|:y}}). It yanks the current line into register <code>A</code> (append to register <code>a</code>).
   
  +
Increment each number at the start of a line, from the current line to end-of-file, by one (the exclamation mark in <code>:normal!</code> means this will work even if Ctrl-A has been mapped to perform a function other than its default of incrementing a number).
Invite further comments...
 
  +
<pre>
  +
:.,$g/^\d/exe "normal! \<C-A>"
  +
</pre>
   
  +
Comment lines containing "DEBUG" statements in a C program.
Hal Atherton
 
  +
<pre>
, April 23, 2002 10:12
 
  +
" using :normal
----
 
  +
g/^\s*DEBUG/exe "norm! I/* \<Esc>A */\<Esc>"
g/foo/s//bar/gc =&gt; run the command s//bar/gc for each of the line
 
  +
" using :substituting
matching foo. It is like running multiple "s//" commands (Hence
 
  +
g/^\s*DEBUG/s!.*!/* & */!
you have to press q for each of the invocation). The
 
  +
</pre>
g in "s///gc" does not imply entire file, it just implies all occurence
 
on a line (or else, it would have substituted only the first)
 
   
  +
Reverse lookup for records (say an address book, with Name at start-of-line and fields after a space).
Arun Easi
 
  +
<pre>
, April 23, 2002 23:33
 
  +
:g/<pattern>/?^\w?p "if only name is interesting
----
 
  +
:g/<pattern>/ka|?^\w?p|'ap "if name and the lookup-line is interesting
Here is one that deletes every other line (adjusting double spaced files):
 
  +
:g/<pattern>/?^\w?|+,/^[^ ]/-1p "if entire record is interesting
  +
</pre>
  +
:''Explanation'' See {{help|:range}} for the meaning of the constructs in the <code><nowiki>[cmd]</nowiki></code> portion of the <code>:g</code> commands.
   
  +
Reverse a file (just to show the ''power of g'').
:g/.*/norm jdd
 
  +
<pre>
  +
:g/^/m0
  +
</pre>
   
  +
:''Explanation'' According to {{help|multi-repeat}}, <code>:g</code> and its cousin <code>:v</code> work in a two-pass manner. The first pass of <code>:g</code> marks every line matching <code>{pattern}</code>, while the second pass (apparently performed starting at the file's beginning and proceeding to the end) performs the <code><nowiki>[cmd]</nowiki></code>. The above use of <code>:g</code> takes advantage of the order the lines are processed in (which is probably okay, though probably not technically guaranteed). It works by first marking every line, then moving the first marked line to the top of the file, then moving the second to the top of the file (above the line moved previously), then the third marked line (again above the previously moved line), and so on until the last line in the file is moved to the top, effectively reversing the file. Note that if <code>:g</code> processed lines in any order other than from top to bottom, this command would not work.
   
  +
Add text to the end of a line that begins with a certain string.
dyang--AT--entropia.com
 
  +
<pre>
, May 30, 2002 9:04
 
  +
:g/^pattern/s/$/mytext
----
 
  +
</pre>
This can be done much simpler:
 
   
  +
==Notes==
:%norm jdd
 
  +
Use <code>:v</code> to reVerse the sense of the search pattern. Example: Delete all lines ''not'' matching ''pattern'':
 
  +
<pre>
pagaltzis()gmx_de
 
, August 6, 2002 15:12
 
----
 
Another cool g feature is to count the number of lines matching /regexp/
 
 
let x=0 | g/regexp/let x=x+1
 
echo x
 
 
Great, if you are editing data files.
 
 
Regards
 
Mike
 
 
mra--AT--frogne.dk
 
, February 10, 2003 4:49
 
----
 
Reverse all the lines in a file:
 
 
:g/^/m0
 
 
I have found that useful . . . honest!
 
 
PK
 
 
 
setanta5--AT--excite.com
 
, March 27, 2003 2:14
 
----
 
Can I do something like this using ":g" (or anything else)
 
 
I have a file which contains following kind of lines
 
 
abc123=1,2,3
 
bcd123=100,200,300
 
abcb123=1,3,4
 
 
I want to convert this to following
 
 
abc123=1,abc,2,abc,3,abc
 
bcd123=100,bcd,200,bcd,300,bcd
 
abcb123=1,abcb,3,abcb,4,abcb
 
 
Basically I want to replace each comma in a line with first few letters, which are coming before 123, of that line surrounded by 2 commas.
 
 
kkgahlot--AT--yahoo.com
 
, September 3, 2003 5:06
 
----
 
To answer kkgahlot's question:
 
 
global // execute "s/\\([=,][^,]*\\)/\\1, " . matchstr (getline ("."), "^.\\{-}\\(123\\)\\--AT--=") . "/g"
 
 
 
To make the whole thing a little more transparent some explanations (from the inside out):
 
 
We want to execute on each line a command like
 
 
s/\([=,][^,]*\)/\1, abc/g
 
 
for each line, but abc gets changed on each line.
 
 
The function
 
 
matchstr (getline ("."), "^.\\{-}\\(123\\)\\--AT--=")
 
 
returns the string that matches the pattern /^.\{-}\(123)\--AT--=/ on the current line. In the given examples this is the text preceding 123= at the beginning of the line. Depending on the actual requierements, a simpler expression like /^[a-z]*/ could work too.
 
 
The command
 
 
execute "s/\\([=,][^,]*\\)/\\1, " . matchstr (getline ("."), "^.\\{-}\\(123\\)\\--AT--=") . "/g"
 
 
assembles the desired substitute command for the current line by joining some static text with the return value of the matchstr function and then executes it.
 
 
As execute works only on the current line, the command
 
 
global // execute ...
 
 
applies it to all line. If only certain lines should be proecessed replace // with some other pattern.
 
 
 
 
'''Anonymous'''
 
, September 3, 2003 12:45
 
----
 
Reverting lines in a file can also be done via
 
:%!tac
 
 
instead of tac, you can also use sort, xxd, xxd -r, cut, your-own-filter
 
 
utzb--AT--gmx.de
 
, November 21, 2003 10:39
 
----
 
too bad :g does not have a /c parameter for confirmed execution of ex commands. Something like the /c used in :&lt;range&gt;s/&lt;PAT&gt;/&lt;REPL&gt;/c for replacing only confirmed pattern locations.
 
 
or does it ??
 
 
'''Anonymous'''
 
, March 29, 2004 7:18
 
----
 
I just want to add that the :g command in vi/ed is the basis for the name for the Unix grep command, i.e. Global Regular Expression Print. The "Print" part described the default behaviour of :g when no command was given. Obviously this behaviour was more useful when using ed.
 
 
jdimpson--AT--yahoo.com
 
, April 14, 2004 10:06
 
----
 
Thank you for the tip
 
 
bsjawle--AT--hotmail.com
 
, August 16, 2004 23:55
 
----
 
Thanks for reminding about the power of :g! I used to use it back when there was only "vi". But together with vim it becomes so much stronger. Now, if someone could explain:
 
 
:g/^/pu _
 
 
I guess I should know and I guess it's an RTFM thinngy. But anyway. =)
 
/PEZ
 
 
pez--AT--pezius.com
 
, December 16, 2004 4:33
 
----
 
The command
 
 
:g/^/pu _
 
 
is the global command with ^ as search pattern. The ^ matches the beginning of a line and
 
therefore each line of the file is a match.
 
The pu _ command is the :put command putting the contents of the _ blackhole register
 
after the current line followed by a newline. The blackhole register _ never contains anything
 
and therefore it can be used to insert an empty line. This is like doing cp /dev/nul empty.file
 
to create an empty file.
 
What the entire command does is putting an empty line after each line of the file.
 
 
 
 
jpaulus--AT--fNrOeeSnPeAt.dMe - NOSPAM
 
, February 22, 2005 12:15
 
----
 
The above note contains a typo. cp /dev/nul empty.file is wrong.
 
cp /dev/null empty.file is right.
 
Doing touch empty.file is another way to create an empty file if it does not exist yet.
 
 
 
 
'''Anonymous'''
 
, February 22, 2005 12:32
 
----
 
I work a lot with coordinate lists that have the following format:
 
 
XXXXXXX.XXXXXX YYYYYYY.YYYYYY
 
 
these lists can be extremely long. Sometimes, the same coordinate appears twice or more times, how can I delete multiple occurences?
 
 
'''Anonymous'''
 
, December 22, 2005 2:02
 
----
 
how can you globally delete lines 'not matching' a pattern
 
 
'''Anonymous'''
 
, March 17, 2006 12:41
 
----
 
Mention should also be made of :g's cousin, :v which is the same except it runs the command on every line that *does not* match the pattern.
 
 
So to delete all the lines that do not match a particular pattern you do
 
 
:v/pattern/d
 
:v/pattern/d
  +
</pre>
   
jonathantan86--AT--hotmail.com
 
, March 18, 2006 2:29
 
 
----
 
----
  +
Some explanation of commands commonly used with <code>:g</code>
Is there way I can use :g to search a pattern and delete from that pattern to the end of line instead of deleting the whole line.
 
  +
<pre>
  +
:2,8co15 "copy lines 2 through 8 after line 15
  +
:4,15t$ "copy lines 4 through 15 to end of document (t == co)
  +
:-t$ "copy previous line to end of document
  +
:m0 "move current line to line 0 (i.e. the top of the document)
  +
:.,+3m$-1 "current line through current+3 are moved to the lastLine-1 (i.e. next to last)
  +
</pre>
   
ra_v_na--AT--rediffmail.com
 
, March 24, 2006 9:21
 
 
----
 
----
  +
Since commands used with :g are Ex commands, searching for help should include the colon.
:g/&lt;pattern&gt;7d does not work ? Is there any way to accompolish this. I want to delete more than 1 lines based on a pattern
 
  +
<pre>
  +
:help :<help-topic>
  +
:help :k "example
  +
</pre>
   
  +
==References==
amjain.gzb--AT--gmail.com
 
  +
*{{help|ex-cmd-index}} provides a list of Ex commands.
, April 4, 2006 6:55
 
  +
*{{help|10.4}} is the section of the user manual discussing the :global command.
----
 
  +
*{{help|multi-repeat}} talks about both the :g and :v commands.
Run a macro on a matching lines
 
(example assuming a macro recorded as 'q'):
 
:g/&lt;pattern&gt;/normal --AT--q
 
g and normal combined is cool.
 
   
  +
==Comments==
  +
Over a range defined by marks ''a'' and ''b'', operate on each line containing ''pattern''. The operation is to replace each ''pattern2'' with ''string''.
  +
<pre>
  +
:'a,'bg/pattern/s/pattern2/string/gi
  +
</pre>
   
noah--AT--noah.org
 
, April 20, 2006 15:20
 
 
----
 
----
  +
Run a macro on matching lines (example assuming a macro recorded as 'q'):
A co-worker keeps asking me how to globally delete lines that do not match a pattern. Very useful.
 
  +
<pre>
 
  +
:g/<pattern>/normal @q
To delete all things matching "pattern", you would do
 
  +
</pre>
:%g/pattern/d
 
 
So to delete the lines that do not match, you negate the pattern using "!", like this
 
:%g!/pattern/d
 
 
This is very useful when trying to make sense of huge logfiles, especially when used with the "or" operator. If I wanted to open a logfile and remove everything that did not match "steve", "May 2", or "addition" (sometimes you're looking for multiple things in a logfile, you get the idea), I would do something like this
 
:%g!/steve\|May 2\|addition/d
 
   
kaan--AT--erdener.org
 
, May 2, 2006 18:41
 
 
----
 
----
  +
To delete (subsequent) duplicate lines from a file:
Regarding the post above by &lt;amjain.gzb--AT--gmail.com&gt;:
 
  +
<pre>
You should be able to do something like this:
 
  +
:g/^\(.*\)\(\r\?\n\1\)\+$/d
:g/&lt;pattern&gt;/ norm d7d
 
  +
:%!uniq
  +
</pre>
   
  +
To just view the duplicates use:
'''Anonymous'''
 
  +
<pre>
, June 2, 2006 16:12
 
  +
/^\(.*\)\(\r\?\n\1\)\+$
----
 
  +
</pre>
To delete (subsequent) duplicate lines from a file:
 
:g/^\(.*\)\(\r\?\n\1\)\+$/d
 
   
To just view the duplicates use:
 
/^\(.*\)\(\r\?\n\1\)\+$
 
 
-Rob (phxrider\at\gmail)
 
 
Anonymous
 
, July 13, 2006 12:39
 
 
----
 
----
  +
Compress multiple occurrences of blank lines into a single blank line
Hi!
 
  +
<pre>
  +
:v/./,/./-j
  +
</pre>
   
  +
Use <code>:helpgrep '\/,\/' *.txt</code> for an explanation.
Сan somebody help me?
 
   
  +
I'll break down this incredible collapse-multiple-blank-lines command for everyone, now that I finally figured out how it works.
How can I copy a result of the command :g/pattern/&#35; from the command-line window?
 
   
  +
First, however, I'll rewrite it this way to illustrate that some of those slashes have totally different meaning than others:
ruslan.gordeev--AT--gmail.com
 
  +
<pre>
, July 18, 2006 2:29
 
  +
:v_._,/./-1join
----
 
  +
</pre>
you can use
 
:g/^/exec "s/^/".strpart(line(".")." ",0,4)
 
(for inserting line numbers)
 
and then
 
:v/&lt;patern&gt;/d
 
...output is desired i think :) ...but it's not very beautiful way :o)
 
then just twice u (undo) to get original content
 
   
  +
Note that to delimit expressions like these, just about any symbol can be used in place of the typical slashes... in this case, I used underscores. What we have is an inverse search (:v, same as :g!) for a dot ('.') which means anything except a newline. So this will match empty lines and proceed to execute [command] on each of them.
uzivatel--AT--szm.sk
 
  +
<pre>
, July 24, 2006 4:19
 
  +
:v_._[command]
----
 
  +
</pre>
Can the search pattern matches also give the number of matches found in the file.
 
Let's say i execute the command similar to
 
   
  +
The remaining [command] is this, which is a fancy join command, abbreviated earlier as just 'j'.
:/&lt;search_pattern&gt;
 
  +
<pre>
In the results while it is searching can it print, the number of matches found for that pattern.
 
  +
,/./-1join
say "30 lines 50 words 100 characters matched" be printed at the command area ?
 
  +
</pre>
   
  +
The comma tells it to work with a range of lines:
  +
<pre>
  +
:help :,
  +
</pre>
   
  +
With nothing before the comma, the range begins at the cursor, which is where that first blank line was. The end of the range is specified by a search, which to my knowledge actually does require slashes. The slash and dot mean to search for anything (again), which matches the nearest non-empty line and offsets by {offset} lines.
  +
<pre>
  +
/./{offset}
  +
</pre>
   
  +
The {offset} here is -1, meaning one line above. In the original command we just saw a minus sign, to which vim assumes a count of 1 by default, so it did the same thing as how I've rewritten it, but simply with one character fewer to type.
msrinirao[at]gmail[dot]com
 
  +
<pre>
, July 26, 2006 4:18
 
  +
/./-1
----
 
  +
</pre>
Increment the number items from current line to end-of-document by one
 
:.,$g/^\d/exe "normal! \&lt;c-a&gt;"
 
   
  +
There is a caveat about join that makes this trick possible. If you specify a range of only one line to "join", it will do nothing. For example, this command tells vim to join into one line all lines from 5 to 5, which does nothing:
Thanks for the above tip..but i am bit curious to know how it works.
 
  +
<pre>
can any one explain me how it's able to increment that means what &lt;c-a&gt; will represent???
 
  +
:5,5join
  +
</pre>
   
  +
In this case, any time you have more than one empty line (the case of interest), the join will see a range greater than one and join them together. For all single empty lines, join will leave it alone.
k.nagakiran--AT--gmail.com
 
, August 20, 2006 23:41
 
----
 
&lt;C-A&gt;
 
means press Ctrl + A keys on keyboard
 
it increments number under cursor in normal mode
 
...but it doesn't work if u have mapped this key (e.g. by vim
 
under windows where are these keys (&lt;C-V&gt;,&lt;C-S&gt;,... - see output of :map command)
 
mapped after installing)
 
   
  +
There's no good way use a delete command with :v/./ because you have to delete one line for every empty line you find. Join turned out to be the answer.
then u can use
 
:unmap &lt;C-A&gt; to remove this mapping temporally (it will work again after new start of vim or command :source &lt;your_PATH&gt;_vimrc)
 
and then try it in normal mode
 
   
  +
This command only merges truly "empty" lines... if any lines contain spaces and/or tabs, they will not be collapsed. To make sure you kill those lines, try this:
  +
<pre>
  +
:v/^[^ \t]\+$/,/^[^ \t]\+$/-j
  +
</pre>
   
  +
Or, to just clean such lines up first,
uzivatel--AT--szm.sk
 
  +
<pre>
, August 23, 2006 1:31
 
----
 
Is there a way to delete from beginning of line (^) up to &lt;pattern&gt; on a line for all lines in a file?
 
 
OR
 
 
delete X characters on each line for Y number of lines?
 
 
Thanks!
 
 
memyselfandi--AT--graffiti.net
 
, August 28, 2006 15:45
 
----
 
to everyone asking "is there a way to match ....... ":
 
The answer is probably yes. Vim uses regular expressions, which are
 
a very powerful way of finding patterns. They take some work to get
 
good at (i've only been using them for 2 weeks), but any time you put
 
into them will be greatly rewarded! And, since you are a Vim user,
 
you are obviously used to at least one power tool that takes some
 
learning but greatly improves your productivity.
 
 
The best way imo to learn regular expressions is
 
1) get a simple cheat sheet for Vim regular expressions
 
2) look through a list of examples, eg:
 
http://www.rayninfo.co.uk/vimtips.html
 
3) any time you're doing a repetitive editing task like deleting all the
 
comment characters from the beginning of a code block, think of
 
how a regular expression might make the job easier &amp; figure out
 
how to do it.
 
 
the Vim manual has lots of stuff on regular expressions, but it's not the
 
easisest to follow. here are some of the help pages:
 
 
bare basics on searching: chapter 3, section 9 (usr_03.txt)
 
a little more comprehensive: chapter 27 (usr_27.txt)
 
pretty in-depth: regexp &amp; search commands (pattern.txt)
 
 
to ra_v_na:
 
 
i'm not sure about :g but :s will work.
 
 
:%s/\(pattern\).*$/\1/
 
 
the % says to do the substitution on every line in the document
 
pattern is the pattern we're searching for
 
the \( and \) stores our pattern in a variable (in our case, variable \1)
 
the .* matches any amount of characters
 
the $ matches the end of the line
 
the \1 is a variable storing pattern
 
so the whole thing replaces pattern and everything following it until the end of the line by the pattern alone
 
 
to memyselfandi:
 
 
your first question:
 
 
:%s/^.*\(pattern\)/\1/
 
 
the % says to do the substitution on every line in the document
 
the ^ says to match the beginning of a line
 
the .* says to match any amount of characters
 
the \( and \) stores our pattern in a variable (in our case, variable \1)
 
"pattern" is whatever pattern you want to search for
 
\1 is a variable holding the contents of the pattern
 
so basically, the whole thing replaces everything from the beginning of the line to the pattern by the pattern alone
 
 
your second question:
 
 
:1,7s/^.\{5\}//
 
 
the 1,7 wold do the replacement on lines 1 through 7. Replace 1 and 7 by whatever you want
 
the ^ says to match the beginning of the line
 
the . says to match any character
 
the \{5\} says to match the preceding character 5 times. Replace 5 by whatever you want
 
so basically, the whole thing deletes the first 5 characters from lines 1 through 7
 
 
Anonymous
 
, September 4, 2006 13:55
 
----
 
Compress multiple occurences of blank lines into a single blank line
 
 
:v/./,/./-j
 
 
cd to the "docs" directory of vim,
 
 
grep '\/,\/' *.txt
 
 
to find occurences of /,/ that can be investigated further to find
 
an explanation of what vim is doing.
 
 
daN.thompOsonS--AT--yaPhAooM
 
, September 16, 2006 18:11
 
----
 
:v/./,/./-j
 
 
I'll break down this incredible collapse-multiple-blank-lines command for everyone, now that I finally figured out how it works.
 
 
First, however, I'll rewrite it this way to illustrate that some of those slashes have totally different meaning than others:
 
 
:v_._,/./-1join
 
 
Note that to delimit expressions like these, just about any symbol can be used in place of the typical slashes... in this case, I used underscores. What we have is an inverse search (:v, same as :g!) for a dot ('.') which means anything except a newline. So this will match empty lines and proceed to execute [command] on each of them.
 
 
:v_._[command]
 
 
The remaining [command] is this, which is a fancy join command, abbreviated earlier as just 'j'.
 
 
,/./-1join
 
 
The comma tells it to work with a range of lines:
 
 
:help :,
 
 
With nothing before the comma, the range begins at the cursor, which is where that first blank line was. The end of the range is specified by a search, which to my knowledge actually does require slashes. The slash and dot mean to search for anything (again), which matches the nearest non-empty line and offsets by {offset} lines.
 
 
/./{offset}
 
 
The {offset} here is -1, meaning one line above. In the original command we just saw a minus sign, to which vim assumes a count of 1 by default, so it did the same thing as how I've rewritten it, but simply with one character fewer to type.
 
 
/./-1
 
 
There is a caveat about join that makes this trick possible. If you specify a range of only one line to "join", it will do nothing. For example, this command tells vim to join into one line all lines from 5 to 5, which does nothing:
 
 
:5,5join
 
 
In this case, any time you have more than one empty line (the case of interest), the join will see a range greater than one and join them together. For all single empty lines, join will leave it alone.
 
 
There's no good way use a delete command with :v/./ because you have to delete one line for every empty line you find. Join turned out to be the answer.
 
 
This command only merges truly "empty" lines... if any lines contain spaces and/or tabs, they will not be collapsed. To make sure you kill those lines, try this:
 
 
:v/^[^ \t]\+$/,/^[^ \t]\+$/-j
 
 
Or, to just clean such lines up first,
 
 
 
:%s/^[ \t]\+$//g
 
:%s/^[ \t]\+$//g
  +
</pre>
   
'''Anonymous'''
 
, October 17, 2006 18:18
 
 
----
 
----
  +
Here is a 'g' version that does the same thing as that last 'v' command
"Is there way I can use :g to search a pattern and delete from that pattern to the end of line instead of deleting the whole line."
 
  +
<pre>
 
  +
:g/^[ <TAB>]*$/,/[^ <TAB>]/-j
Not that I have found!
 
  +
</pre>
 
I use the ${var%string} from bash/ksh instead
 
 
 
ask2--AT--runbox.com
 
, October 30, 2006 23:37
 
----
 
I have a malformed XML file with a structure like this:
 
 
&lt;authors&gt;
 
&lt;author&gt;
 
Blogs, Joe
 
&lt;/author&gt;
 
&lt;author&gt;
 
Smith, Fred
 
&lt;/author&gt;
 
&lt;author&gt;
 
Jones, David
 
&lt;/author&gt;
 
&lt;/authors&gt;
 
 
How do I use :g and the join command to get rid of those new lines, so the structure ends up like this:
 
 
&lt;authors&gt;
 
&lt;author&gt;Blogs, Joe&lt;/author&gt;
 
&lt;author&gt;Smith, Fred&lt;/author&gt;
 
&lt;author&gt;Jones, David&lt;/author&gt;
 
&lt;/authors&gt;
 
 
What I need to do is search for '&lt;author&gt;' and then join the next line (-1j, right?), and then the next one (containing &lt;/author&gt;) to the previous one.
 
These XML files are large (&gt;1000 lines) so a global find and replace would be great. Thanks in advance!
 
 
tatlar--AT--yahoo.com
 
, November 1, 2006 9:50
 
----
 
Figured out my malformed XML issue in the note above, in a 2 step process:
 
 
1) Find and replace '&lt;author&gt;\n' (where \n is a newline) with '&lt;author&gt;':
 
 
:%s/&lt;author&gt;\n/&lt;author&gt;/g
 
   
  +
However, all the above blank line merging method fails to merge multiple blank lines at the end of a file. The solution is to add then remove an extra line at the end of the file. As such this is the complete blank line compressor command...
2) Use :g to find '&lt;/author&gt;' and do a negative join (join with previous line):
 
  +
<pre>
  +
:$s/$/\\rZ/
  +
:g/^[ <TAB>]*$/,/[^ <TAB>]/-j
  +
:$d
  +
</pre>
   
  +
Or in the form of an easy to use macro, which also tries to return to to your original place in the file.
:g/&lt;\/author&gt;/-1j
 
  +
<pre>
  +
:map QE mz:$s/$/\\rZ/<CR>:g/^[ <TAB>]*$/,/[^ <TAB>]/-j<CR>Gdd`z
  +
</pre>
   
tatlar--AT--yahoo.com
 
, November 1, 2006 10:17
 
 
----
 
----
  +
As always, There's More Than One Way To Do It:
I am searching for a regexp on a line with thousands of line, while doing :g/&lt;regexp&gt;/p it prints the whole line, I want it to only print the regexp i.e. \1 variable so that I can copy all those lines manually in a file, and is there any way inside vim only to re-direct the regexp results found into a file.
 
  +
<pre>
  +
:%s/^$\n^$//g
  +
</pre>
  +
This uses a substution (s/foo/bar/) that matches two consecutive blank lines and turns them into one. Applied globally (%), and multiple times to the same line (g), this works exactly as you'd want it to.
   
mail_the_cv--AT--yahoo.com
 
, January 28, 2007 23:46
 
 
----
 
----
  +
Another way to collapse empty lines, including whitespace, is:
<!-- parsed by vimtips.py in 0.627565 seconds-->
 
  +
<pre>
  +
:%s/^\_s\+/\r/g
  +
</pre>
  +
<code>\_s</code> matches whitespace (space and tab) ''including'' end of line, <code>\+</code> matches 1 or more of those, as many as possible, <code>\r</code> inserts carriage return specific to file format (unix-dos-mac).

Revision as of 10:34, 27 January 2014

Tip 227 Printable Monobook Previous Next

created 2002 · complexity intermediate · author Arun Easi · version 6.0


The global command :g is very useful. Here are some examples showing the power of :g.

Brief explanation of :g

:[range]g/<pattern>/cmd

This will act on the specified [range] (default whole file), by executing the Ex command cmd (An Ex command is one starting with a colon (':')) for each line matching <pattern>. Before executing cmd, "." is set to the current line.

Examples

Display context (5 lines) for all occurrences of a pattern.

:g/<pattern>/z#.5
" Same, but with some beautification.
:g/<pattern>/z#.5|echo "=========="

Delete all lines matching a pattern.

:g/<pattern>/d

Delete all lines that do not match a pattern.

:g!/<pattern>/d

Delete all blank lines (^ is start of line; \s* is zero or more whitespace characters; $ is end of line)

:g/^\s*$/d

Double space the file (^ is start of line which matches each line).

:g/^/pu =\"\n\"
" Alternative (:put inserts nothing from the blackhole register)
:g/^/pu _

Copy all lines matching a pattern to end of file.

:g/<pattern>/t$

Move all lines matching a pattern to end of file.

:g/<pattern>/m$

Copy all lines matching a pattern to register 'a'.

qaq:g/<pattern>/y A
Explanation qaq is a trick to clear register a (qa starts recording a macro to register a, then q stops recording, leaving a empty). y A is an Ex command (:help :y). It yanks the current line into register A (append to register a).

Increment each number at the start of a line, from the current line to end-of-file, by one (the exclamation mark in :normal! means this will work even if Ctrl-A has been mapped to perform a function other than its default of incrementing a number).

:.,$g/^\d/exe "normal! \<C-A>"

Comment lines containing "DEBUG" statements in a C program.

" using :normal
g/^\s*DEBUG/exe "norm! I/* \<Esc>A */\<Esc>"
" using :substituting
g/^\s*DEBUG/s!.*!/* & */!

Reverse lookup for records (say an address book, with Name at start-of-line and fields after a space).

:g/<pattern>/?^\w?p "if only name is interesting
:g/<pattern>/ka|?^\w?p|'ap "if name and the lookup-line is interesting
:g/<pattern>/?^\w?|+,/^[^ ]/-1p "if entire record is interesting
Explanation See :help :range for the meaning of the constructs in the [cmd] portion of the :g commands.

Reverse a file (just to show the power of g).

:g/^/m0
Explanation According to :help multi-repeat, :g and its cousin :v work in a two-pass manner. The first pass of :g marks every line matching {pattern}, while the second pass (apparently performed starting at the file's beginning and proceeding to the end) performs the [cmd]. The above use of :g takes advantage of the order the lines are processed in (which is probably okay, though probably not technically guaranteed). It works by first marking every line, then moving the first marked line to the top of the file, then moving the second to the top of the file (above the line moved previously), then the third marked line (again above the previously moved line), and so on until the last line in the file is moved to the top, effectively reversing the file. Note that if :g processed lines in any order other than from top to bottom, this command would not work.

Add text to the end of a line that begins with a certain string.

:g/^pattern/s/$/mytext

Notes

Use :v to reVerse the sense of the search pattern. Example: Delete all lines not matching pattern:

:v/pattern/d

Some explanation of commands commonly used with :g

:2,8co15  "copy lines 2 through 8 after line 15
:4,15t$   "copy lines 4 through 15 to end of document (t == co)
:-t$      "copy previous line to end of document
:m0       "move current line to line 0 (i.e. the top of the document)
:.,+3m$-1 "current line through current+3 are moved to the lastLine-1 (i.e. next to last)

Since commands used with :g are Ex commands, searching for help should include the colon.

:help :<help-topic>
:help :k   "example

References

Comments

Over a range defined by marks a and b, operate on each line containing pattern. The operation is to replace each pattern2 with string.

:'a,'bg/pattern/s/pattern2/string/gi

Run a macro on matching lines (example assuming a macro recorded as 'q'):

:g/<pattern>/normal @q

To delete (subsequent) duplicate lines from a file:

:g/^\(.*\)\(\r\?\n\1\)\+$/d
:%!uniq

To just view the duplicates use:

/^\(.*\)\(\r\?\n\1\)\+$

Compress multiple occurrences of blank lines into a single blank line

:v/./,/./-j

Use :helpgrep '\/,\/' *.txt for an explanation.

I'll break down this incredible collapse-multiple-blank-lines command for everyone, now that I finally figured out how it works.

First, however, I'll rewrite it this way to illustrate that some of those slashes have totally different meaning than others:

:v_._,/./-1join

Note that to delimit expressions like these, just about any symbol can be used in place of the typical slashes... in this case, I used underscores. What we have is an inverse search (:v, same as :g!) for a dot ('.') which means anything except a newline. So this will match empty lines and proceed to execute [command] on each of them.

:v_._[command]

The remaining [command] is this, which is a fancy join command, abbreviated earlier as just 'j'.

,/./-1join

The comma tells it to work with a range of lines:

:help :,

With nothing before the comma, the range begins at the cursor, which is where that first blank line was. The end of the range is specified by a search, which to my knowledge actually does require slashes. The slash and dot mean to search for anything (again), which matches the nearest non-empty line and offsets by {offset} lines.

/./{offset}

The {offset} here is -1, meaning one line above. In the original command we just saw a minus sign, to which vim assumes a count of 1 by default, so it did the same thing as how I've rewritten it, but simply with one character fewer to type.

/./-1

There is a caveat about join that makes this trick possible. If you specify a range of only one line to "join", it will do nothing. For example, this command tells vim to join into one line all lines from 5 to 5, which does nothing:

:5,5join

In this case, any time you have more than one empty line (the case of interest), the join will see a range greater than one and join them together. For all single empty lines, join will leave it alone.

There's no good way use a delete command with :v/./ because you have to delete one line for every empty line you find. Join turned out to be the answer.

This command only merges truly "empty" lines... if any lines contain spaces and/or tabs, they will not be collapsed. To make sure you kill those lines, try this:

:v/^[^ \t]\+$/,/^[^ \t]\+$/-j

Or, to just clean such lines up first,

:%s/^[ \t]\+$//g

Here is a 'g' version that does the same thing as that last 'v' command

:g/^[ <TAB>]*$/,/[^ <TAB>]/-j

However, all the above blank line merging method fails to merge multiple blank lines at the end of a file. The solution is to add then remove an extra line at the end of the file. As such this is the complete blank line compressor command...

:$s/$/\\rZ/
:g/^[ <TAB>]*$/,/[^ <TAB>]/-j
:$d

Or in the form of an easy to use macro, which also tries to return to to your original place in the file.

:map QE mz:$s/$/\\rZ/<CR>:g/^[ <TAB>]*$/,/[^ <TAB>]/-j<CR>Gdd`z

As always, There's More Than One Way To Do It:

:%s/^$\n^$//g

This uses a substution (s/foo/bar/) that matches two consecutive blank lines and turns them into one. Applied globally (%), and multiple times to the same line (g), this works exactly as you'd want it to.


Another way to collapse empty lines, including whitespace, is:

:%s/^\_s\+/\r/g

\_s matches whitespace (space and tab) including end of line, \+ matches 1 or more of those, as many as possible, \r inserts carriage return specific to file format (unix-dos-mac).