I have this file over here.

    <ul class="social-icons">
        <li><a href=""><span class="social_linkedin_square"></span></a></li>
    <ul class="other-icons">
        <li><a href=""><span class="other-icon"></span></a></li>

I'm trying to only print all the list items in the file using the global command.
(i.e. lines containing <li>...</li> NOTE: <li> and </li> can be on separate lines)

I tried typing this in the command line:


But for whatever reason it's including </ul> <ul class="other-icons"> rather than only the <li>...</li> lines. Alongside with a range error:

        <li><a href=""><span class="social_linkedin_square"></span></a></li>
    <ul class="social-icons">
        <li><a href=""><span class="another"></span></a></li>
E16: Invalid range

Isn't that weird since this global command matches only lines containing <li> and then the print command runs on each of those lines ending with </li> so it should stop the match at that same line? What am I missing?

UPDATE: The command works correctly only if <li> and </li> are on separate lines which is interesting.

  • You sure you gave us the same global command that you ran? Because the one above doesn't look right to me and, indeed, causes an Invalid Range error when I run it. – B Layer Feb 14 at 6:58
  • This is what I get when I run :g/<li>/.,/<\/li>/p <li><a href=""><span class="social_linkedin_square"></span></a></li> </ul> <ul class="social-icons"> <li><a href=""><span class="another"></span></a></li> E16: Invalid range – mkayyash Feb 14 at 7:49
  • You should include that information in your question. (Hit the "Edit" link to do so.) – B Layer Feb 14 at 10:00
  • 1
    @BLayer just edited it – mkayyash Feb 14 at 18:47

When you have / characters in your pattern is is better to use another separator, for instance | (see :help :g).

I am guessing that too many separators are confusing the parsing engine.

The following command will do what you want with the example you gave (the <li> elements are all on a single line)


Here I am using | as a separator and .* captures everything up to </li>.

  • 1
    I think the original intent was « for every line with the start of a list item, print from that line to the line with the closing list item » – D. Ben Knoble Feb 14 at 21:21
  • Thank you for the answer. So this works assuming <li>and </li> are on the same line which is not always the case. But to be honest, I'm just mostly puzzled at why the specific command that I ran :g/<li>/.,/<\/li>/p would not work correctly. – mkayyash Feb 14 at 21:40
  • @mkayyash I edited my answer with a guess :-)) – guntbert Feb 14 at 21:47
  • Appreciate trying! I replaced <li> with liopen and </li> with liclose in the buffers. Then I ran :g/liopen/.,/liclose/p and got the same error so probably not a separator issue. – mkayyash Feb 14 at 21:51
  • Actually if liopen and liclose are on separate lines. Everything works correctly. – mkayyash Feb 14 at 22:08

Reading through the documentation I found the answer. This is not related to the global command but mainly due to cmdline-ranges operating on the NEXT line matching the pattern rather than same or next line which I originally thought.

:h cmdline-ranges
    /{pattern}[/]   the next line where {pattern} matches     *:/*

So running :g/<li>/.,/<\/li>/p is akin to running :.,/<\/li>/p on each line containing <li>. And since /pattern/ matches starting from the NEXT line the original expression was basically unable to find a closing </li> on the last match which causes the range error.

  • @guntbert edited to add more details. Let me know if it's missing anything else. – mkayyash Feb 15 at 22:42
  • Looks good, thanks for your contribution. – guntbert Feb 17 at 11:16

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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