I've managed to set up my org-file-apps mostly the way I want it, although one thing remains: I'd prefer if executable files were opened directly in Emacs since most of them are scripts that I'd like to edit instead of run.

My current settings are:

(setq org-file-apps
'(("\\.docx\\'" . default)
  ("\\.x?html?\\'" . default)
  ("\\.pdf\\'" . default)
  ("\\.log\\'" . emacs)
  (sh-mode . emacs) ; <-- didn't work, it detects the executable bit then runs
  (auto-mode . emacs)))

I was looking around for something along the lines of executable-mode or the like but came up short. Is there some other symbol to do this (I'm aware of the problem that it will open binaries in the editor but that seldom how I link)?

  • 1
    In org-version 9.0.5 sh-mode is none of the possible values of the file identifier.
    – Tobias
    Jun 27, 2017 at 14:21

2 Answers 2


In your current settings the line (sh-mode . emacs) is not valid. Documentation states that only following entries: string, directory, remote, auto-mode, t and system are allowed.
This means if your shell-scripts do not have a special filename pattern you have to work around.

To work around you could:
A) add, at the end of org-file-apps alist (after (auto-mode . emacs)), the line: (t . emacs).
Then everything which drops to there will be loaded into emacs.
But beware: This means you have to catch other stuff, you never want loaded in emacs before this line.

B) misuse the groups feature. This is way more cool. Documentation states this:

Regular expression which contains (non-shy) groups: Match links where the whole link, including "::", and anything after that, matches the regexp. In a custom command string, %1, %2, etc. are replaced with the parts of the link that were matched by the groups. For backwards compatibility, if a command string is given that does not use any of the group matches, this case is handled identically to the second one (i.e. match against file name only). In a custom lisp form, you can access the group matches with (match-string n link).

Example: (".pdf::(\d+)'" . "evince -p %1 %s")
to open [[file:document.pdf::5]] with evince at page 5.

Also it states that sexp are allowed as command:

sexp A Lisp form which will be evaluated. The file path will be available in the Lisp variable `file'.

So you could do:

1) set your org-file-apps (adapt this to your needs):

(setq org-file-apps
'(("\\.log\\'" . emacs)
  (".*::\\(editme\\)\\'" . (my-find-file-wrapper file))))

2) define your own opening function:

(defun my-find-file-wrapper (f)
    (message "fooo")
    (find-file f))

3) write your links with following style [[file:skriptfilename::editme]]

Note: instead of using my-find-file-wrapper you could use a regular elisp function which eats the file parameter.

Of course if all your shell scripts have the extension .sh, you could just replace (sh-mode . emacs) with ("\\.sh\\'" . emacs) . ;)

  • tested with org version 8.2.10
    – jue
    Jun 27, 2017 at 20:16
  • Nice! I'll try it out (second technique I think) Jun 28, 2017 at 6:39
  • @JacobOscarson good you like it. The second technique took me a while from idea to a working setup. Is it solving your problem?
    – jue
    Jun 29, 2017 at 11:29
  • Works as a charm! Jun 30, 2017 at 6:22

I intercept all files:

  • without an extension
  • filename only consists of alphanumeric and "_"

and refuse to open if target is a binary.

(defun my/open-if-not-binary (path link)
  (let ((buf (find-file-noselect path)))
    (if (eq 'no-conversion (with-current-buffer buf buffer-file-coding-system))
        (progn (kill-buffer buf)
               (message "target is a binary file, add `C-u' if you insist"))
      (switch-to-buffer buf))))

(add-to-list 'org-file-apps '("/[[:alnum:]/]+/[[:alnum:]_]+$" . my/open-if-not-binary))

refs: detecting binary

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.