2

What is the difference between doing :% [...] and :g [...]. Does g require a regex to filter out what lines to apply to, or does it apply to all lines if no regex is given? For example:

To insert a " at the beginning of every line:

:% normal!I"

I'm guessing the equivalent g command would be:

:g/./ normal!I"

So, does % essentially translate to:

/./ in a command?

2 Answers 2

1

These two are not really the same. In your example, :g/./ normal!I" will only prepend non-empty lines with a ", but it will not prepend the " to empty lines, which the :%normal!I" will do.

Yes, :g always needs a pattern and only acts on the lines that match that pattern. If you use an empty pattern (//), Vim will reuse the last pattern you used in a previous search, :s or :g command.

A closer similar to the % range would be using :g/^/, which is a pattern that will match all lines, including empty ones.

Using :g will have other side effects not in %, since when you use a pattern it is then saved as the last used pattern, which also presents itself visually if you have 'hlsearch' enabled.

Also note that :g itself takes a range! You can use :10,20g/pattern/command to execute the command only on lines between 10 and 20 which also match the passed pattern. In fact, :g/^/ normal!I" is equivalent to :%g/^/ normal!I". In other words, :g defaults to the % range when one is not passed explicitly.

The % range is exactly equivalent to :1,$, the range of lines between the first and the last one in the buffer.

2
  • 1
    great answer, thank you very much for the clarification on the above.
    – David542
    Jun 21, 2020 at 2:38
  • @David542 I tried to cover all angles 😁
    – filbranden
    Jun 21, 2020 at 2:50
2

One other subtlety not noted by filbranden, is that the manner in which the two commands process the set of lines is a little different. The simplest example of the difference is probably to compare these two commands:

:%join
:g/^/join

The first will concatenate every line in your buffer into a single line. The second will concatenate every other line to its adjacent line (so you end up with half as many lines as before).

:help :global explains why :g works in this way:

The global commands work by first scanning through the [range] lines and marking each line where a match occurs (for a multi-line pattern, only the start of the match matters).

In a second scan the [cmd] is executed for each marked line, as if the cursor was in that line. For ":v" and ":g!" the command is executed for each not marked line. If a line is deleted its mark disappears.

(emphasis mine)

1
  • oh very interesting and good to know, thanks for the thorough explanation!
    – David542
    Jun 22, 2020 at 16:30

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.