Is there any way to make vim treat bash variables (anything prefixed with a $, really) as distinct words? For instance, with the following lines:

"name $suffix.ext"

with the cursor somewhere in $suffix, the motion diw should leave me with "name .ext" and "name.ext", respectively.

My primary reason for wanting this is to enable me to use some mappings I have for wrapping words in quotes/parens/etc with bash variables. I'm okay with changing the mapping as long as it still works with normal words, but I would prefer not to have to make this a syntax-specific mapping (but if there's no easy way around that, I can deal with it). (Here's one of the quote wrapping mappings I referenced: nnoremap <leader>" viw<esc>a"<esc>hbi"<esc>lel)

Initially, I thought I could do this with set iskeyword, but I could only make that work for cases such as name $suffix.ext, and it then makes performance for name$suffix.ext cases worse, in my opinion.

My other thoughts were along the lines of getting vim to recognize $ and [any word separator] as either

  • a matching pair (like { and }( this seems like too much potential for bad side effects))
  • or a "tag" (i.e., like html/xml tags that dit) recognizes (never messed with those, so I wasn't sure where to begin there)

2 Answers 2


This can be a case deserving a new text object. With Kana's framework (vim-textobj-user) in place, it would be something like this:

" define av/iv to select a bash variable:
call textobj#user#plugin('bash', {
        \  'avar': {
        \   'pattern': '\$\w\+\>',
        \   'select': [ 'av'],
        \  },
        \  'ivar': {
        \   'pattern': '\$\zs\w\+\>',
        \   'select': [ 'iv'],
        \  },
        \  'var': {
        \   'pattern': ['\${', '}'],
        \   'select-i': [ 'iV'],
        \   'select-a': [ 'aV'],
        \  },
        \ })

... and then I can use 'div', 'yav' etc. to delete inside the object (skipping the $) or yank the whole variable, and use iV/aV for the ${var} format.

I hope a more enterprising soul can unify those formats, to use a single code letter (e.g. v) in both cases.

However, this won't work with the mapping you mentioned for a few reasons. First, the mapping would need to be recursive to take advantage of the new text object. Second, the map would need to use different movements to reach the start/end of the word. Staying approximately similar to what you have already, this mapping should work:

nmap <leader>" vav<esc>`>a"<esc>`<i"<esc>f"

This uses the selection based movements `> and `< to reach the end and beginning of the selection, respectively. However, this might not play well with other mappings/plugins/etc that you may have, so be wary of that. Furthermore, this will not allow the mapping to work for normal words. To do that you would have to modify the text object to overwrite the default w behavior.

  • This was definitely better than what I had, but while it didn't give me exactly what I wanted (due to not working with my mappings for quote-wrapping), it didn't require much tweaking to make it do what I needed. I changed 'pattern': '\$\w\+\>' to 'pattern': '\$\?\w\+\>', 'select': [ 'av'] to 'select': [ 'aw'], and altered my mapping from viw<esc>a"<esc>hbi"<esc>lel to vaw<esc>`>a"<esc>"<i`<esc>f". Accepting since it did answer the root question, even if it didn't quite work for my specific case. Jun 12, 2015 at 18:58

You could add $ to the iskeyword option for shell scripts in your ~/.vimrc:

augroup shellscript
    autocmd FileType sh setlocal iskeyword+=$
augroup END

Alternatively, you could do that in ~/.vim/after/ftplugin/sh.vim:

setlocal iskeyword+=$
  • 5
    OP mentions that he's already tried this in his question. If you're posting this because it's definitely the only possible solution, you should probably say so explicitly.
    – Rich
    Mar 14, 2015 at 9:25

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.