如何在新建python时自动插入 shebang?

就是在文件头部插入:

#!/usr/bin/env python # -*- coding: utf-8 -*-

两行

(eval-after-load 'autoinsert
  '(define-auto-insert '(python-mode . "python utf-8 encode")
     '("Description: "
       "#!/usr/bin/env python" \n
       "# -*- coding: utf-8 -*-" \n)))
(auto-insert-mode)  ;;; Adds hook to find-files-hook

https://www.emacswiki.org/emacs/AutoInsertMode

2 个赞

假如愿意自己动手的话:

(defun chunyang-python-insert-shebang ()
  (when (and (eq major-mode 'python-mode)
             (bobp) (eobp))
    (insert "#!/usr/bin/env python # -*- coding: utf-8 -*-\n")))

(add-hook 'find-file-hook #'chunyang-python-insert-shebang)
1 个赞

autoinsert 和 hook 的问题在于

  1. 不是所有的文件都需要 shebang
  2. 想给一个旧文件添加 shebang,这些自动触发的机制就不太好使了

我更习惯使用 snippet

# -*- mode: snippet -*-
# name: bang
# key: !
# --
#!/usr/bin/env python
$0

只需按 !<TAB> 两个键也不是很麻烦,而且可以根据场景定义不同的 shebang 参数 (在同一个 mode 下)

2 个赞

其实我用的也是snippet:

# -*- mode: snippet -*-
# name: bomb
# key: !
# --
#!/usr/bin/env python3
# # -*- coding: utf-8 -*-
# author:Samray <[email protected]>
$0

只是提问的同学说:

如何在新建python时自动插入 shebang?

我默认是在所有的 python 都插入 shebang 了

1 个赞

结合auto-insert与yasnippet 模版

;; 利用yasnipet模版,在创新新文件时,自动在文件中插入相应的模版

(autoload 'yas-expand-snippet "yasnippet")
(defun my-autoinsert-yas-expand()
  "Replace text in yasnippet template."
  (yas-expand-snippet (buffer-string) (point-min) (point-max)))

;;; auto-insert
(setq-default auto-insert-directory (concat user-emacs-directory "auto-insert-template/"))
(unless noninteractive (auto-insert-mode 1))  ;;; Adds hook to find-files-hook

(setq-default auto-insert-query nil) ;;; If you don't want to be prompted before insertion
(define-auto-insert "\\.el$" ["el-auto-insert" my-autoinsert-yas-expand])
(define-auto-insert "\\.erl$" ["erl-auto-insert" my-autoinsert-yas-expand])
(define-auto-insert "\\.hrl$" ["hrl-auto-insert" my-autoinsert-yas-expand])
(define-auto-insert "\\.c$"  ["c-auto-insert" my-autoinsert-yas-expand])
(define-auto-insert "\\.cpp$" ["c++-auto-insert" my-autoinsert-yas-expand])
(define-auto-insert "\\.cc$" ["c++-auto-insert" my-autoinsert-yas-expand])
(define-auto-insert "\\.cs$" ["csharp-auto-insert" my-autoinsert-yas-expand])
(define-auto-insert "\\.org$" ["org-auto-insert" my-autoinsert-yas-expand])
(define-auto-insert "\\.tex$" ["tex-auto-insert" my-autoinsert-yas-expand])
(define-auto-insert "\\.py$" ["py-auto-insert" my-autoinsert-yas-expand])
(define-auto-insert "\\.go$" ["go-auto-insert" my-autoinsert-yas-expand])

;; (define-auto-insert "\\.org$" "org-auto-insert")
(provide 'conf-yas-auto-insert)

然后在 .emacs.d/auto-insert-template/py-auto-insert 内 插入你想要的模版内容就行 如

#  -*- coding:utf-8 -*-
__author__ = '`user-login-name`'

可以参考我的一些配置

2 个赞

判断下文件是否为空就够了,Auto Insert 就是这么做的,退一步讲,的确不要的话,一个 Undo 就能行了。不过这是用户需求和习惯的问题,谈不上好坏。比如我既不用 auto-insert-mode 也不用 snippet,我手打。

1 个赞

https://www.gnu.org/software/emacs/manual/html_node/autotype/Executables.html

看了下上面的文档,貌似在进入 sh-mode 时,会自动调用 executable-set-magic 填写 shebang。但是实际测试时又没有,不知道哪里的问题?

executable-set-magic被调用是在sh-set-shell函数里面,而sh-set-shell函数在 sh-mode-map里默认绑定在C-c :上。

不过,在sh-mode开启的时候,会自动运行

;; Parse or insert magic number for exec, and set all variables depending
;; on the shell thus determined.
(sh-set-shell
 (cond ((save-excursion
          (goto-char (point-min))
          (looking-at "#![ \t]?\\([^ \t\n]*/bin/env[ \t]\\)?\\([^ \t\n]+\\)"))
        (match-string 2))
       ((not buffer-file-name) sh-shell-file)
       ;; Checks that use `buffer-file-name' follow.
       ((string-match "\\.m?spec\\'" buffer-file-name) "rpm")
       ((string-match "[.]sh\\>"     buffer-file-name) "sh")
       ((string-match "[.]bash\\>"   buffer-file-name) "bash")
       ((string-match "[.]ksh\\>"    buffer-file-name) "ksh")
       ((string-match "[.]mkshrc\\>" buffer-file-name) "mksh")
       ((string-match "[.]t?csh\\(rc\\)?\\>" buffer-file-name) "csh")
       ((string-match "[.]zsh\\(rc\\|env\\)?\\>" buffer-file-name) "zsh")
       ((equal (file-name-nondirectory buffer-file-name) ".profile") "sh")
       (t sh-shell-file))
 nil nil)

sh-set-shell的3个参数分别是 shell, no-query-flag, insert-flag。 所以可以看到,在打开sh-mode的时候是不会插入shebang的。

同时又有一个变量executable-insert会影响shebang的更新:

executable-insert description
nil Do nothing.
t Insert or update magic number.
other Insert or update magic number, but mark as unmodified.

所以想自动更新shebang,有几种方式:

  1. M-x运行executable-set-magic手工更新 (python-mode下同样适用)
  2. C-c :触发sh-set-shell
  3. 通过设置sh-shell这个local variable来间接达到调用sh-set-shell
  4. 利用advice机制自己动手修改sh-set-shell的逻辑

注: executable-set-magic同时也会让文件加上x执行权限,除非它被executable-magicless-file-regexp这个正则匹配到了。

1 个赞

@Youmu 多谢解释,那看来最方便的方式还是 yasnippet,然后加上

  (add-hook 'after-save-hook 'executable-make-buffer-file-executable-if-script-p)

这样脚本就能自动加上执行权限了。