Setting foldmethod=marker, I can highlight a few lines, press zf to fold them. By default vi will add {{{ and }}} at the ends of the beginning and ending lines. I am working on shell scripts with filename.sh. I find that vim is clever enough to add #{{{ and #}}} if that particular line is (ending with) code, which the preceding # is intended to comment out the curly brackets. However vi does not add a space before #, which makes this #{{{ comment mess up with the code indeed.

The correct way would be adding #{{{ and #}}}. set foldmarker=\ #\ {{{,\ #\ }}} does not work, as vi will add an extra # sign, without leading space, before the custom fold markers.

In fact, we do not need vi to be so smart to distinguish between codes or comments. Just blindly adding #{{{ and #}}} (with preceding spaces) will work in both cases. This won't harm in the comments.

1 Answer 1


Vim uses the 'commentstring' option to start a comment if this option is not empty. The placeholder %s inside the 'commentstring' option is replaced with the opening and closing foldmarkers, respectively.

The default commentstring for shell scripts is #%s, so there is no leading space. You can change that with set commentstring=\ #%s. Because this option is currently only used to add markers for folding (see :help 'commentstring') you should not notice unwanted side effects.

See :help fold-create-marker for the details.

  • Thank you @JürgenKrämer. I do not know why only set commentstring=\ #%s in ~/.vimrc has no effect. With reference to another post, wrap it inside augroup does the job perfectly. It turns out I am using setlocal foldmarker=\ {{{,\ }}}, augroup MyCommentStringGroup \n autocmd FileType sh setlocal commentstring=\ #%s \n augroup END which gives me very nice zf markups.
    – midnite
    May 26, 2022 at 9:28
  • 1
    @midnite You can check where this option was last set with :verbose set commentstring?. I would guess it is set by the standard sh filetype plugin. In that case you can override it by putting setlocal commentstring=\ #%s in a file called ~/.vim/after/ftplugin/sh.vim. This file will get loaded by Vim after the standard filetype plugin and is IMHO the best place if you want to override the default settings -- even more so, if you want to change more than one setting. May 27, 2022 at 7:15
  • Thanks you @JürgenKrämer again. I get it now. Yes you are right. It was set in /usr/share/vim/vim82/ftplugin/sh.vim and I can override it. I will keep this best practice. For setlocal commentstring=\<tab>#%s, I actually typed the <tab> literally. I found that \tdoes not work. Any better suggestion to specify <tab> in the setting files?
    – midnite
    May 27, 2022 at 12:11
  • 1
    For every global option there is an identically named special variable with a leading ampersand, and for every local variable there is one with a leading l:&. They are aliased to the actual options. You can use these variables in "normal" assignments where you provide the option value as a number or a string. In string values the normal rules for special characters apply, so for your example you can use let &l:commentstring="\t#%s" to include a tab. May 27, 2022 at 12:32
  • Yeah. Bingo. Thank you @JürgenKrämer. Now I learn a lot more. let &l:commentstring="\t#%s" works. l:& should be a typo. It should be a leading &l: instead.
    – midnite
    May 27, 2022 at 14:12

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.