読者です 読者をやめる 読者になる 読者になる

executable-find

exec-path 内に指定の実行ファイルがあるか、現在の OS の実行ファイル拡張子を補いつつ検索します。
見付かった場合はパスを文字列として返します。見付からなかった場合は nil が返ります。

実行結果
(executable-find "grep")    ;=> "/usr/bin/grep"
(executable-find "nowhere") ;=> nil
使用例
  1. exec-path 内に
    1. fastri-server があり
    2. fri がある場合に
    3. ri-emacs があれば ri-ruby-script へ setq し
    4. ri-ruby を load する
  2. 以上が全て non-nil を返した場合に続きを実行する
  (and
   (executable-find "fastri-server")
   (executable-find "fri")
   (setq ri-ruby-script (executable-find "ri-emacs"))
   (load "ri-ruby" t)
;;...snip...
http://github.com/elim/dotemacs/tree/1b1e99d1fb077d26f7e0bde1a827e5c338eb0ab2/init-ruby.el

実装

HEAD
(defun executable-find (command)
  "Search for COMMAND in `exec-path' and return the absolute file name.
Return nil if COMMAND is not found anywhere in `exec-path'."
  ;; Use 1 rather than file-executable-p to better match the behavior of
  ;; call-process.
  (locate-file command exec-path exec-suffixes 1))
http://cvs.savannah.gnu.org/viewvc/emacs/emacs/lisp/files.el?revision=1.1005&view=markup
Emacs21 時代
(defun executable-find (command)
  "Search for COMMAND in exec-path and return the absolute file name.
Return nil if COMMAND is not found anywhere in `exec-path'."
  (let ((list exec-path)
        file)
    (while list
      (setq list
            (if (and (setq file (expand-file-name command (car list)))
                     (let ((suffixes executable-binary-suffixes)
                           candidate)
                       (while suffixes
                         (setq candidate (concat file (car suffixes)))
                         (if (and (file-executable-p candidate)
                                  (not (file-directory-p candidate)))
                             (setq suffixes nil)
                           (setq suffixes (cdr suffixes))
                           (setq candidate nil)))
                       (setq file candidate)))
                nil
              (setq file nil)
              (cdr list))))
    file))
http://cvs.savannah.gnu.org/viewvc/emacs/emacs/lisp/progmodes/executable.el?revision=1.26.4.4&view=markup

ではこれの初出はいつ頃なのかと探りましたところ、どうやら Emacs CVS 内最古の executable.el でも実装されていたようです。

初出?
(defun executable (command)
  "If COMMAND is an executable in $PATH its full name is returned.  Else nil."
  (let ((list exec-path)
	path)
    (while list
      (setq list (if (and (setq path (expand-file-name command (car list)))
			  (file-executable-p path)
			  (not (file-directory-p path)))
		     nil
		   (setq path nil)
		   (cdr list))))
    path))
http://cvs.savannah.gnu.org/viewvc/emacs/emacs/lisp/progmodes/executable.el?revision=1.1&view=markup

1995 年のことですね。

実はこの関数に気付かないで、ほぼ同じ実装の locate-executable という関数書いて使っていました。

13 年も前からある関数を使っていなかったなんて……。よく調べないと無駄に再実装してしまうものですね。お恥ずかしい*1

*1:きっと他にも ~/.emacs.d 内に組込関数の再実装が転がっていると思います >_<