I want to make a function that will set the correct major mode based on the interpreter used for a script.

I don't want to include extensions in my scripts (because that can be annoying if making cli tools), but I still want the appropriate mode to be set when I edit those scripts.

This is to be done by reading the first line of the script where we find the sh-bang.

for example, if the script starts with


I want shell-script-mode to be called on the buffer.

If the interpreter is


I want python mode to be called.

This is what I currently have:

(defun set-major-mode (interpreter-name)
  "Set major mode acording to INTERPRETER-NAME."
  (message (concat "INTERPRETER: " interpreter-name))
  (when (string-match interpreter-name "bash")
    (shell-script-mode 1)
    (message "Setting Shell script mode."))
  (when (string-match interpreter-name "python")
    (python-mode 1)
    (message "Setting python mode."))
  (when (string-match interpreter-name "")
    (message "Not setting an interpreter"))

(defun get-interpreter-name (file-name)
"Get the interpreter described in the first line of FILE-NAME."
  (let ((saved-point (point)))
    (goto-line 0)
     (file-name-nondirectory (buffer-substring-no-properties (line-beginning-position) (line-end-position))))
    (goto-char saved-point))

(defun choose-mode-for-file-without-extension ()
  "Choose what major mode to use for files without extensions."
  (let ((file-name (file-name-nondirectory (buffer-file-name))))
    (message (concat "FILE OPENED: " file-name))
    (if (eq (string-match "[[:alnum:]]\\.[[:alnum:]+$]" file-name) nil)
        (get-interpreter-name file-name))

(add-hook 'find-file-hook 'choose-mode-for-file-without-extension)

The messages get called as expected, however when I try to open a shell script (file without the .sh extension), shell-script-mode does not get called. Any tips?

EDIT solved

Turns out that my script is fine. The path on my sh-bang was wrong. The file I was trying to open had


which is of course wrong.

1 Answer 1


Such a functionality is already built into Emacs. Interpreters are mapped to modes with the variable interpreter-mode-alist. It contains by default

("python[0-9.]*" . python-mode)

and many other interpreters. It does work for bash and python out of the box.

As an aside, you should use absolute path for interpreters, e.g. #!/bin/bashinstead of #!bin/bash.

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.