I want to search an entire file for the string --- when it appears at the beginning of a line. I then want to insert a newline before each instance of that string.

In my .vimrc file, I added this command:

let @p=":1,$s/^---/^M---/"

When I execute it, it does not insert the newline character. Instead it ignores everything from the ^M on, so it replaces the --- with a null string, removing the 3 dashes from each line that contains them at the beginning.

What is wrong with my @p command? I doesn't seem to recognize the ^M character. Is this not allowed in a search and replace command? I can do this manually, by the way, by simply typing the exact same command at the : prompt at the bottom of the file.

I also tried:

let @p=":1,$s/^---/^M^[---/"

(added an escape after the newline) - this gave me the exact same result. Looks like it's ignoring the escape along with the rest of the replace section.

Can someone tell me the correct way to do this? I do want to keep these commands in the vimrc file, because I edit a lot of files that have the same set of commands (and involve several macros, all of which work fine except this one), so I don't want to recreate the same macros every time I open a new file.

Thank you!

  • DO you insist to be vi script? Or you will accept awk, sed....? Commented Aug 16, 2022 at 7:39
  • How did you add the ^M? Ctrl-V Ctrl-M?
    – muru
    Commented Aug 16, 2022 at 7:40
  • Linux newline is not Control-M (carriage return) but rather Control-J (line feed).
    – Sotto Voce
    Commented Aug 16, 2022 at 11:33
  • @RomeoNinov This generates a vi macro, so it seems this is needed during editing.
    – Philippos
    Commented Aug 16, 2022 at 12:41
  • @SottoVoce But a carriage return is the character that is generated when hitting the return key, and that's what matters here. Try to enter :%s/-/^M/g in vim and see all dashes get replaced by line breaks.
    – Philippos
    Commented Aug 16, 2022 at 12:45

1 Answer 1


Remember that the characters in a script will act as if they were typed. So on ^M a carriage return will be executed. So you need to write

let @p=":1,$s/^---/^V^M---/^M"

because this is what you would type when manually recording the macro. Of course, to write this, you need to type ctrlV, then ctrlV, then ctrlV and finally ctrlM.

Also note that you need a final ^M at the end to really execute the command, not just place it in the buffer.

And btw you can simplify 1,$ to % and use & instead of repeating the pattern, so you can write

let @p=":%s/^---/^V^M&/^M"
  • If that was the problem then it's probably better to use \r instead. In the replacement of :s, Vim takes \r to mean newline and \n to mean the null character
    – muru
    Commented Aug 16, 2022 at 12:52
  • If you use \r in a script, the same thing will happen, I'm afraid. I never found a way to solve the problem other than I wrote it. If you have something else proved to work, please let us know.
    – Philippos
    Commented Aug 16, 2022 at 13:03
  • let @p=":1,$s/^---/\\r---/\n" should work In double-quoted strings, the ` for \r` will need to be escaped.
    – muru
    Commented Aug 16, 2022 at 13:12
  • @Philippos Thank you, that solved the problem! I'm curious why you need the extra ^M at the very end. You said it was to execute the command and not just place it in the buffer. I have a lot of other macros, and all I do is type @# (where # is the letter used to access the macro in the register) and most of my macros just execute, without a ^M at the end of the string. I'm wondering why this one is different.
    – Bastette
    Commented Aug 16, 2022 at 15:01
  • 1
    @Bastette because this one leaves normal mode to go to command line mode, and types out a command. But that command needs to be executed, otherwise it'd just be setting there with the command filled in. So the final ^M or (\n in my variant) acts as the Enter key executing that command.
    – muru
    Commented Aug 16, 2022 at 15:20

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .