When I am writing blog posts using reStructuredText, I have F5 bound to running an external script with current filename using %. The external script generates temporary file with template, which I can preview in browser with. The post title is extracted from the filename.

Inevitably, characters like \' or ! are used sometimes. If you have used shell long enough, you will know those characters may cause issues if they are not quoted or escaped correctly.

Since I am just a normal Vim user, not really have much knowledge and experience of coding for Vim configuration. But this time, I managed to put together stuff to get away from escaping issue.

My original keybinding is as the following:

map <F5> <ESC>:w<CR>:!gen-blog-rst.sh '%'<CR>

It saves the file, then run the gen-blog-rst.sh script. As you can see \'%\' definitely will have issues with \' character. I found out there is a Vim function shellescape() which does what I expect:

:echo shellescape("\"blah\" 'foorbar' blah!")
" outputs the following string
'"blah" '\''foorbar'\'' blah!'

You can safely pass to :!some_command as an argument. It will be like running (my default shell is Bash):

bash -c some_command '"blah" '\''foorbar'\'' blah!'

This some_command will get that long word from $1.

The problem is when using :!{cmd}, I can not put anything function in it, it is basically a plain string be passed to your default shell. I don’t know if Vim has something like Command Substitution in Bash to work in string, if it does, let me know.

The solution I found for this part is to use :exec[ute] to wrap it up:

:exec '!gen-blog-rst.sh ' . shellescape(@%)

So, the final map is:

map <F5> <ESC>:w<CR>:exec '!gen-blog-rst.sh ' . shellescape(@%)<CR>

Note that @% is used for the function, instead of just %. I used this to update my vimrc.