I want to create a function that I can call to replace a specific string pattern with md5sum of current buffer.

I have no experience writing VimL before and can't figure out the way to do it.

This is what I roughly have in my mind:

" Calculate text hash and replace the old one
function! HashBuffer()
  :redir @a
  " Will this work? Is this a buffer contents or previously save file?
  :!md5sum %
  :redir END

  " replace with @a (How?)

Usage example:

Let say I have a file, I am working on


the content of file ....

I want the hash to be calculate when I manually :call HashBuffer()

# %%%HASH-1d4171a91c31af2c59acb89a042836e1%%%

the content of file ....

It's obviously not working but I don't have any idea what to do next.

  • 3
    When you save the file, calculate the md5sum and insert it into the file, you have to save the file again. This changes the file, so you need to calculate the m5sum and insert it into the file. This is an endless loop.
    – Ralf
    May 20, 2019 at 10:05
  • Oh, never think of that. OK, I change my goal to just only when I manually call the function.
    – wizzup
    May 20, 2019 at 10:06

2 Answers 2


You could try the following:

"" calculate text hash and replace the old one
function! HashBuffer()
  let md5=trim(system('md5sum ' . expand('%') . ' | cut "-d " -f1'))
  %s/%%%\<HASH.*%%%/\='%%%' . 'HASH-' . md5 . '%%%'/

A few notes:

  • expand('%') returns the current file name.
  • | cut "-d " -f1 only returns the md5sum, but cuts of the file name
  • trim(...) is used to trim the trailing newline (trim() was introduced in Vim 8.0.1630 or so, if you have an older versions I could provide a replacement)

The interesting part is the regex. This is written more complicated than needed, so if you ever run the function on its source code, the source code will not be destroyed. Lets simplify it first:

%s/%%%\<HASH.*%%%/\='%%%' . 'HASH-' . md5 . '%%%'/
%s/%%%HASH.*%%%/\='%%%HASH-' . md5 . '%%%'/

The \< was removed, it just matches the "start of a word". See :h /\<.

The interesting part is the replacement String:

\='%%%HASH-' . md5 . '%%%'

The leading \= is called "sub-replace-special". When the replacement string starts with this, the rest is interpreted as a VimScript expression. Here we just concatenate the leading string with the MD5 and the trailer.

  • Work like a charm!
    – wizzup
    May 20, 2019 at 11:21

EDIT After our discussion in chat here is the final function you need:

function! HashBuffer()
    let hashedContent = system("md5sum " . expand('%')) 
    execute '%s/HASH.*/HASH-' . split(hashedContent, ' ')[0]

First we use :h system() to get the result of the external command md5sum <filename> in a variable and we use :h expand() to get the actual filename.

In my system md5sum returns a result of the form {hash} {filename}, as you don't want the filename we use :h split() to get only the hash.

Finally we use :h execute() to build the susbtitution command you want to use with the content of the variable.

I think you only need one command:


Which basically filters the content of the full buffer (%) through the external command (!) md5sum.

In my setup the file



e70ad0b62c1f427ae49ce73b9c09155c  -

And if you want to make that a function, the following should work:

function! HashBuffer()

You probably want to read

  • I'm not sure I understand what you mean: In a vim without configuration using :%!{cmd} replaces the content of the current buffer with the output of the command. No new buffer is created and you don't need to do any substitution.
    – statox
    May 20, 2019 at 9:46
  • Let us continue this discussion in chat.
    – wizzup
    May 20, 2019 at 9:57

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.