1

I have a sample text:

123
456

If I delete the first line, why does

:silent! execute 'g/123/d' | execute 'g/456/d'

work while

:silent! g/123/d | g/456/d

doesn't work, unless I bring back the first line, so that both patterns are matched?

Shouldn't :silent! make it execute completely (by suppressing Neovim's Error messages) regardless of whether it succeeds in finding a match or not?

Or maybe I'm misunderstanding the mechanics of | or <Bar> aka pipe character in this context?

2 Answers 2

2

In your example you have a file with a single line 456. If you run:

:g/123/d | g/456/d

you get a Pattern not found message on the first command and the second one does not run. It is a message and not an error (see comments), hence that is not the reason why the second command is not running. From Neovim's :help :bar:

Note that this is confusing (inherited from Vi): With ":g" the '|' is included in the command, with ":s" it is not.

To be able to use another command anyway, use the ":execute" command.

As @D.BenKnoble pointed out, the execute is making sure that the :g does not swallow the pipe. By using execute, you are doing as instructed by the documentation.

5
  • 1
    I'm not sure this is correct. If :s/foo/bar fails, so does :execute 's/foo/bar' | echom 'hi' without echoing hi. The difference seems primarily to be that :g/123/d | g/456/d considers d | g/456/d as the on-each-line command (:help :bar). the execute prevents :g from eating the bar, so you have two separate commands.
    – D. Ben Knoble
    Jun 20, 2023 at 19:08
  • @D.BenKnoble you are right in that I am wrong. execute does stop on error of the input command. Moreover, from the help on search-commands: 'When no match is found you get the error: E486 Pattern not found Note that for the :global command, you get a normal message "Pattern not found", for Vi compatibility.' So s throws an error but g only prints "Pattern not found". I will look into this a bit more and edit my answer. Jun 21, 2023 at 9:16
  • @D.BenKnoble you are right, I will edit my answer. Jun 21, 2023 at 9:25
  • @MehdiSlimani There is :silent! command in my original line: :silent! g/123/d | g/456/d that you and @D.BenKnoble seem to have overlooked. This should change how the line is executed, shouldn't it? After all, errors & other messages are being suppressed, so I think | shouldn't stop execution no matter what is the outcome, whether a pattern match is found or not.
    – danko
    Jun 21, 2023 at 12:53
  • 1
    @danko the command is effectively parsed as [silently] [for each line containing 123, do] [delete, then if that succeeded, [for each line containing 456, do [delete]]]. With execute, you have [silently] [for each line containing 123, do] [delete], then if that succeeded (which it will because of [silently]), [for each line containing 456, do] [delete]. See the difference?
    – D. Ben Knoble
    Jun 21, 2023 at 13:06
2

The difference seems primarily to be that :g/123/d | g/456/d considers d | g/456/d as the on-each-line command (:help :bar). The :execute prevents :global from eating the bar, so you have two separate commands. (Details on the structure at the end.)

This matters: in :g/123/d | g/456/d, if 123 is not found, _none of d | g/456/d runs. But in :execute 'g/123/d' | execute 'g/456/d', if 123, is not found, first d is not run, then execute 'g/456/d' is not run because the previous command errored.

Finally, by prefixing the first command with :silent! (:silent does not consume |, so only the first command is silenced), you guarantee that execute 'g/456/d' runs no matter what.


A small representation of the parsing differences:

  • :silent! g/123/d | g/456/d: [silently] [for each line containing 123, do] [delete, then if that succeeded, [for each line containing 456, do [delete]]]
  • :silent! execute 'g/123/d' | execute 'g/456/d': [[silently] [for each line containing 123, do] [delete]], then if that succeeded (which it will because of [silently]), [[for each line containing 456, do] [delete]].

Extract from :help :bar to justify parsing:

These commands see the '|' as their argument, and can therefore not be
followed by another Vim command:
[…]
    :global
1
  • 1
    Excerpt from :help :bar helped me understand your statement "The difference seems primarily to be that (...)", namely the following: These commands see the '|' as their argument, and can therefore not be followed by another Vim command (a list of commands follows): (...) :global (:g) (...) Once again, RTFM does wonders!
    – danko
    Jun 21, 2023 at 13:49

Your Answer

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

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