I've noticed in bash/shell it highlights $(...) in red, for example:

enter image description here

However, if I change the syntax from ft=sh to ft=bash, it does not do this:

enter image description here

What's the reason for this? Am I doing something wrong with the ft=sh, or why is that highlighted in red when it's a legitimate syntax construct?


This is because the original Bourne shell only understands `...` - the standard $( ... ) syntax was added later. From syntax/sh.vim:

" $() and $(()): {{{1
" $(..) is not supported by sh (Bourne shell).  However, apparently
" some systems (HP?) have as their /bin/sh a (link to) Korn shell
" (ie. Posix compliant shell).  /bin/ksh should work for those
" systems too, however, so the following syntax will flag $(..) as
" an Error under /bin/sh.  By consensus of vimdev'ers!

You can set the variable g:is_bash to tell the sh syntax file that sh is actually bash, if indeed it is actually bash (does sh --version show the Bash version?). Or you can set g:is_posix if sh is POSIX compliant.

  • This "consensus of vimdev'ers" comment can be traced back to a Vim 7.001 commit from back in 2004, so it's been around for over 15 years, maybe even more than twenty... Looks like back in 2008 people were already asking about it and someone objected because Solaris /bin/sh still wouldn't recognize it. Maybe in 2020 it's time to revert that already? – filbranden Jul 15 '20 at 4:48
  • 1
    Looking at the manpage, that still seems to be the case for Oracle Solaris 11.1. Sigh. Maybe g:is_posix should be set by default and g:is_sh should be set only for systems with the broken sh. – muru Jul 15 '20 at 4:57
  • Yeah... But is Solaris even relevant anymore? I thought even Oracle was mostly pushing Linux at this point... – filbranden Jul 15 '20 at 5:04
  • 1
    I went through the discussions there and in bugs.debian.org/cgi-bin/bugreport.cgi?bug=361177, and I don't know if we have a compelling argument against "backwards compatibility" there. Think it's worth posting again on vim-dev? – muru Jul 15 '20 at 7:52
  • 1
    @David542 so macOS, where /bin/sh is not a symlink to /bin/bash but a copy or hardlink, which is why it's not guessing correctly. Put let g:is_posix = 1 in your vimrc. – muru Jul 15 '20 at 19:39

Shell originally used only backticks for command substitution:

less `find . -type f`

But these do not nest and suffer from other problems. Bash (and probably ksh, but I’m not up on the history there) used $() as a newer, improved command substitution.

But that explains the difference and while the filetype matters—in fact, the shebang (#! line) matters! If you use /bin/sh, you should only use POSIX sh features. Otherwise, use the path to a known interpreter and use it’s features.

As pointed out in the comments, POSIX allows the newer command substitution, so it should be safe even in sh scripts.

  • 1
    $( ... ) is perfectly fine for POSIX. (See, e.g, even the older versions of the standard.) – muru Jul 15 '20 at 3:30
  • How should I fix this then? Should I set an autocommand that if ft=sh set ft=bash ? – David542 Jul 15 '20 at 19:11
  • 1
    @David542 try :let g:is_bash = 1 in your vimrc—:help ft-sh-syntax – D. Ben Knoble Jul 15 '20 at 19:12

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.