90

My Vim editor auto highlights PHP files (vim file.php), HTML files (vim file.html) and so on.

But when I type: vim file and inside it write a Bash script, it doesn't highlight it.

How can I tell Vim to highlight it as a Bash script?

I start typing #!/bin/bash at the top of the file, but it doesn't make it work.

Mateusz Piotrowski
  • 8,029
  • 10
  • 53
  • 79
never_had_a_name
  • 90,630
  • 105
  • 267
  • 383

13 Answers13

96

Are you correctly giving the shell script a .sh extension? Vim's automatic syntax selection is almost completely based on file name (extension) detection. If a file doesn't have a syntax set (or is the wrong syntax), Vim won't automatically change to the correct syntax just because you started typing a script in a given language.

As a temporary workaround, the command :set syn=sh will turn on shell-script syntax highlighting.

Mark Rushakoff
  • 249,864
  • 45
  • 407
  • 398
  • 4
    but the most scripts dont have a .sh extension? should i put it as a .sh extension just to make it work? is it best practice to name your scripts? and its bash...so its still .sh? – never_had_a_name Apr 05 '10 at 02:56
  • 4
    @ajsie: I'm not sure what scripts you're using, but most `bash` scripts I encounter do indeed have a `.sh` suffix. To really specify *bash* as opposed to just `sh`, you would use the `#!/bin/bash` shebang line on a `.sh` file. – Mark Rushakoff Apr 05 '10 at 02:59
  • 1
    just type :set ft=sh and your good to go, OR, prefix your script with a modeline: "# vim:ft=sh" without the quotes of course, AND, i suggest getting something better than the sh filetype highlighter for bash scripts because it does not recognize things properly, some examples are ${VAR: 1:2} substrings, ;& or ;;& <- end-of-case modifiers, and many of the bash-specific keywords are not recognized either. Of course, dont get one that is crappy because there ARE SOME BAD ONES circulating around out there, ive used a couple that were way worse than the sh.vim default. – osirisgothra Oct 04 '14 at 12:08
  • 2
    If a file does not have an extension (as many shell scripts used as commands do) then Vim will look at the first line to see a shebang of either `#!/bin/sh` or `#!/bin/bash` to determine the file type either `ft=sh` or `ft=text` in the case no shebang exists. – Sukima Apr 16 '15 at 12:26
  • 5
    @MarkRushakoff, giving bash scripts a `.sh` extension is in many circles considered poor form. See for instance the factoid bot used by the Freenode #bash channel's relevant entry: http://wooledge.org/~greybot/meta/.sh – Charles Duffy May 23 '16 at 21:05
  • 5
    ...to quote: "Don't use extensions for your scripts. Scripts define new commands that you can run, and commands are generally not given extensions. Do you run `ls.elf`? Also: bash scripts are *not* sh scripts (so don't use `.sh`) and the extension will only cause dependencies headaches if the script gets rewritten in another language. See http://www.talisman.org/~erlkonig/documents/commandname-extensions-considered-harmful" – Charles Duffy May 23 '16 at 21:05
  • 5
    ...extensions on shell scripts are universally accepted as a Good Idea when a script is intended to be *sourced as a library* (just as one uses a `.py` extension for Python *modules* but not Python *scripts* located in the PATH) -- but in that case the extension should correctly reflect which shell the script can be correctly parsed by; `.sh` implies "compatible with all POSIX shells", which is not generally accurate for a *bash* script. – Charles Duffy May 23 '16 at 21:07
  • 1
    The `sh` syntax appears to highlight POSIX shell; it does not highlight Bash-specific syntax. – Thanatos Mar 01 '17 at 22:19
49

The answers so far are correct that you can use the extension (like .sh) or a shebang line (like #!/bin/bash) to identify the file type. If you don't have one of those, you can still specify the file type manually by using a modeline comment at the top or bottom of your file.

For instance, if you want to identify a script without an extension as a shell script, you could add this comment to the top of your file:

# vim: set filetype=sh :

or

# vim: filetype=sh

That will tell vim to treat the file as a shell script. (You can set other things in the modeline, too. In vim type :help modeline for more info.)

bryant
  • 991
  • 1
  • 8
  • 7
  • 1
    Interestingly, in my environment, the final `:` makes this modeline work, whereas without the final `:`, this modeline doesn't register. The help documentation shows a form of a modeline that does not end in `:`. – orluke Nov 15 '12 at 16:24
  • 1
    That is interesting. The help documentation (with `:help modeline`) tells two differences: (1) The version with the final `:` "is compatible with some versions of Vi", and (2) without the final `:` you don't use the `set` keyword. Since you can put any text after the modeline, the final `:` works with or without the `set` keyword. – bryant Nov 20 '12 at 14:02
  • 2
    If the modeline seems to have no effect, try `set modeline` in `~/.vimrc`, see [this answer](http://superuser.com/q/323712/72223) – Tino Oct 27 '15 at 13:33
  • 2
    As I noted on the other answer that suggests this, `sh` appears to highlight POSIX shell, not bash. Notably, it flags valid bash syntax as errors, which is rather annoying. – Thanatos Mar 01 '17 at 22:21
28

Actually syntax highlighting is a feature of vim not vi. Try using vim command and then do

:syntax on.

Gaurav Khare
  • 2,203
  • 4
  • 25
  • 23
  • 1
    For me too. You can add the line "syntax on" to your .vimrc file. – teu Jun 02 '15 at 11:30
  • 4
    This was the solution for me on Mac OS X 10.10.3. Added a .vimrc file to my home directory using `vim ~/.vimrc` and adding `syntax on` to the file then closing with `:x` – James Owers Oct 09 '15 at 11:02
24

I came to this answer looking for specifically how to highlight bash syntax, not POSIX shell. Simply doing a set ft=sh (or equivalent) will result in the file being highlighted for POSIX shell, which leaves a lot of syntax that's valid in bash highlighted in red. To get bash highlighting:

" Set a variable on the buffer that tells the sh syntax highlighter
" that this is bash:
let b:is_bash = 1
" Set the filetype to sh
set ft=sh

Note that if your ft is already sh, you still need the set command; otherwise the let doesn't take effect immediately.

You can make this a global default by making the variable global, i.e., let g:is_bash = 1.

:help ft-sh-syntax is the manual page I had to find; it explains this, and how to trigger highlighting of other flavors of shell.

Thanatos
  • 42,585
  • 14
  • 91
  • 146
17

Vim can also detect file types by inspecting their contents (like for example if the first line contains a bash shebang), here is a quote from filetype.txt help file:

If your filetype can only be detected by inspecting the contents of the file

Create your user runtime directory. You would normally use the first item of the 'runtimepath' option. Example for Unix:

:!mkdir ~/.vim

Create a vim script file for doing this. Example:

if did_filetype()   " filetype already set..
    finish      " ..don't do these checks
endif
if getline(1) =~ '^#!.*\<mine\>'
    setfiletype mine
elseif getline(1) =~? '\<drawing\>'
    setfiletype drawing
endif

See $VIMRUNTIME/scripts.vim for more examples. Write this file as "scripts.vim" in your user runtime directory. For example, for Unix:

:w ~/.vim/scripts.vim

The detection will work right away, no need to restart Vim.

Your scripts.vim is loaded before the default checks for file types, which means that your rules override the default rules in $VIMRUNTIME/scripts.vim.

Matteo Riva
  • 24,728
  • 12
  • 72
  • 104
  • 1
    I've tried both putting this in the .vimrc and .vim/scripts.vim, but neither has worked. It only works if I manually type in the commands once I've started vim. What am I doing wrong? – Eddy Nov 20 '12 at 17:06
  • @Eddy Probably you need `set modeline` in `~/.vimrc`, see [this answer](http://superuser.com/q/323712/72223) – Tino Oct 27 '15 at 13:32
10

Vim can detect the file type reading the first line. Add the following line as first line.

#!/bin/sh
apaderno
  • 28,547
  • 16
  • 75
  • 90
Arun Karikalan
  • 132
  • 1
  • 5
4

For those who have a variant of this question i.e. how to enable syntax highlighting on bash files without .sh extension automatically when opened...

Add filetype on in your .vimrc. This enables file type detection by also considering the file's contents. For example, bash scripts will be set to sh file-type. However, typing the #! won't trigger file type detection on a new file created with vim and you will need to use set ft=sh in that case. For more info, type :h filetype in vim.

As mentioned in the comments, you will need to use this in conjuction with syntax enable to turn on highlighting.

Or you could use :filetype detect. From the doc:

Use this if you started with an empty file and typed text that makes it possible to detect the file type. For example, when you entered this in a shell script: "#!/bin/csh".

Mudassir
  • 1,136
  • 1
  • 11
  • 29
2

Once you add the shebang at the top of the file, save it and reload it (e.g. :w|e) and syntax coloring can kick in.

See also Vim inconsistently syntax highlighting bash files, the accepted answer may help as well.

dash-tom-bang
  • 17,383
  • 5
  • 46
  • 62
1

To toggle syntax highlight on/off while you're inside the editor.

Turn on

:syntax on

Turn off

:syntax off

Run this to always have syntax highlighting on when opening vim.

echo ":syntax on" >> ~/.vimrc
Alec Mather
  • 742
  • 5
  • 20
0

Probably the easiest way to get syntax highlighting on a new file, is to just reload it after writing the shebang line. A simple :w :e will write out the file, reload it, and interprete the shebang line you have just written to provide you with the appropriate syntax highlighting.

cmaster - reinstate monica
  • 38,891
  • 9
  • 62
  • 106
0

If you already know the file-type before opening the script or if you're creating a new script without an extension which is common, you can pass it to vim on the command-line like so:

vim -c 'setfiletype sh' path/to/script
vim -c 'setfiletype python' path/to/script
Edge-Case
  • 161
  • 1
  • 5
0

vim already recognizes many file types by default. Most of them work by file extensions, but in a case like this, vim will also analyze the content of the file to guess the correct type.

vim sets the filetype for specific file names like .bashrc, .tcshrc, etc. automatically. But a file with a .sh extension will be recognized as either csh, ksh or bash script. To determine what kind of script this is exactly, vim reads the first line of the file to look at the #! line.

If the first line contains the word bash, the file is identified as a bash script. Usually you see #!/bin/bash if the script is meant to be executed directly, but for a shell configuration file using a simple # bash would work as well.

If you want to look at the details, this is implemented in $VIMRUNTIME/filetype.vim.

raimue
  • 4,322
  • 1
  • 21
  • 31
  • Uhm, actually I wanted to post this somewhere else. But I guess the answer fits here as well :-) – raimue Sep 16 '11 at 23:38
-1

When you create a new file, only the filename detection comes into play; content detection (#!/bin/bash) doesn't apply if you type it after creating a new buffer.

The sensible thing is to just do :set ft=bash the first time around, and the next time you edit it, the #!/bin/bash will set the right filetype automatically.

hobbs
  • 223,387
  • 19
  • 210
  • 288
  • 1
    At my side `ft=bash` needs to read `ft=sh`. Also I needed `set modeline` in `~/.vimrc` to make it work, see [this answer](http://superuser.com/q/323712/72223) – Tino Oct 27 '15 at 13:36