如何让Emacs使用我的.bashrc文件?

22

我需要在Emacs中使用$PATH来运行一些命令。我该如何让Emacs使用它?我是从Ubuntu仓库安装的Emacs。

我需要在Emacs中使用$PATH来运行一些命令,该怎么做呢?我是从Ubuntu仓库安装的Emacs。


https://dev59.com/c3M_5IYBdhLWcg3wZSTX - Vivek Goel
这个答案似乎是一个完美的解决方案。 - Yantao Xie
《DotFiles文章》涵盖了bash点文件的具体加载细节,并提供了背景上下文,以更好地理解本问答主题中讨论的过程。 - Y. E.
9个回答

44

这里有一个技巧我使用,可以确保我的GUI Emacs始终看到与shell中相同的$PATH

(defun set-exec-path-from-shell-PATH ()
  (let ((path-from-shell (replace-regexp-in-string
                          "[ \t\n]*$"
                          ""
                          (shell-command-to-string "$SHELL --login -i -c 'echo $PATH'"))))
    (setenv "PATH" path-from-shell)
    (setq eshell-path-env path-from-shell) ; for eshell users
    (setq exec-path (split-string path-from-shell path-separator))))

(when window-system (set-exec-path-from-shell-PATH))

在OS X上,图形化的Emacs将无法获取用户shell对$PATH的定义,因此这个技巧对我在该平台上的使用很有帮助。
更新:这段代码现已发布为一个elisp库,名为exec-path-from-shell,可以在MELPA中安装包。

这解决了Ubuntu 13.04中相同的问题(我使用软件包管理器进行安装)。 - Anake
1
它似乎没有使用别名。虽然从名称上不会期望它使用别名。是否有什么方法也获取正常bash的别名? - Zelphir Kaltstahl
Emacs 永远不会使用你的 Bash 别名,抱歉:这些别名仅在 Bash 会话内可用。这段代码和 exec-path-from-shell 包只是让 Emacs 能够可靠地定位与 Bash 会话中可见的相同可执行文件和脚本。 - sanityinc
我做错了什么吗?既不是bash函数,还是其他问题? - Welgriv
@Welgriv 不,函数的工作方式类似于bash别名,因此我上面的评论也适用于它们。 - sanityinc
请查看Hugues的回答,该回答还涵盖了别名。 - Y. E.

21

给出了一种更通用的解决方案(不仅设置PATH变量和别名)。请参见https://dev59.com/nGct5IYBdhLWcg3wQ7Qy#12229404,关键是要设置:

(setq shell-command-switch "-ic")

添加"-i"参数将强制Bash shell进入交互模式,从而导致读取~/.bashrc文件。此外,"-i"会覆盖默认的"-c"(执行以下命令)。


1
似乎比被接受的答案更好,因为它允许使用Bash函数。 - Welgriv
在MacOS上,使用这个设置,我保留了~/.bash_profile中的所有内容,然后在~/.bashrc中添加了一行source ~/.bash_profile。就这么简单。最终,我的$PATH和方便的别名可以在EmacsM-x shell-command中顺利使用。 - Y. E.

3
如果您的环境变量没有被捕获,可能是由于emacs启动方式的问题。检查菜单项或其他选项,并尝试将 emacs 更改为 bash-c emacs

1

您可以将路径设置添加到 /etc/profile.d 中,例如:

# /etc/profile.d/path.sh
export PATH="$PATH:/usr/local"

在Ubuntu中,我记得所有的会话都会源自你的~/.xsessionrc,所以你也可以在这个文件中设置GUI应用程序的路径。

1
我为 sourcing 我的 .bash_profile 想出了类似的东西。如果你只关心 PATH,上面的其他答案之一更简单。
它的工作原理是执行 source ~/.bash_profile ; echo post-env; env,然后丢弃 "post-env" 之前的所有内容,接着解析出 "env" 命令打印的 "key=value" 格式中的值。
它可能不能完美地处理每种情况,但对我来说已经足够好了。
;;-------------------------------------------------------
;; begin sourcing of .bash_profile

;; only do this on Mac OS X
(when (string= system-type "darwin")
  ;; require common lisp extensions, for search
  (require 'cl)


  (defun src-shell-unescape (string)
    ;; replace \n \t \r \b \a \v \\
    ;; and octal escapes of the form \0nn

    (replace-regexp-in-string
     "\\\\\\([ntrbav]\\|\\(\\\\\\)\\|\\(0[0-7][0-7]\\)\\)"
     (lambda (str)
       ;; interpret octal expressions
       ;; of the form "\0nn"
       (let ((char1 (aref str 1)))
     (cond ((= ?0 (aref str 1))
        (byte-to-string
         (+ (* (- (aref str 2) ?0) 8)
            (- (aref str 3) ?0))))
           ((eq char1 ?n) "\n")
           ((eq char1 ?t) "\t")
           ((eq char1 ?r) "\r")
           ((eq char1 ?b) "\b")
           ((eq char1 ?a) "\a")
           ((eq char1 ?v) "\v")
           ((eq char1 ?\\) "\\\\")
           (t "")))) string))

  (defun src-set-environment-from-env-output(env-output)
    ;; set the environment from shell's "env" output
    (let ((lines (split-string env-output "\n" t)))
      (dolist (line lines)
    (let ((idx-equals (search "=" line)))
      (when (and (not (eq idx-equals nil))
             (> idx-equals 1))
        (let  ((key (substring line 0 idx-equals))
           (value (substring line (+ idx-equals 1))))
          (setenv key (src-shell-unescape value))
          ;; (message "%s = %s" key value)
          ))))))

  (defun src-source-shell-file (file-name)
    ;; if your shell is sh rather than bash, the "source " may need
    ;; to be ". " instead
    (let* ((command (concat "source '"  file-name "'; echo 'post-env'; env"))
       (output (shell-command-to-string command))
       (idx-post-env (search "post-env" output)))
      (if (eq nil idx-post-env)
      (message "Didn't find expected output after sourcing %s. Found: %s" file-name output)
    (let ((trimmed-output (substring output idx-post-env)))
      ;; (message "trimmed-output: %s" trimmed-output)
      (src-set-environment-from-env-output trimmed-output)))))



  (src-source-shell-file (expand-file-name "~/.bash_profile")))


;; end sourcing of .bash_profile
;;-------------------------------------------------------

0
如果在启动emacs的终端中设置了$PATH,则可以通过命令M-! <your command> RET执行系统命令。

0

有许多Emacs软件包可以更新$PATH环境变量和'exec-path'。这是因为Emacs不假设BASH相关文件(如“~/.bashrc”)中的定义。

在任何非从终端shell执行的程序中所需的所有定义都必须移动到“~/.profile”中,这些定义在系统启动时加载。

一些旧系统需要手动从“/etc/profile”中加载用户配置文件。


0

这应该是一条评论,但格式不正确。@Hueges的答案对我有用,但它会导致dired模式出现问题。有更强的elisp能力的人可能会做得更好,但对我来说它有效。

;; temporarily set shell-command-switch to -ic until function completes
(defun wrap-shell-command (func &rest args) 
  (let ((current-shell-command-switch shell-command-switch)) 
    (setq shell-command-switch "-ic") 
    (apply func args) 
    (setq shell-command-switch current-shell-command-switch)))

;; usage
(wrap-shell-command 'shell-command "func-define-in-bashrc" "other" "args")


0
;; set shell-command-switch to -ic only for async-shell-command
(defun pre-command-hook-fn ()
  "."
  (if (string= current-minibuffer-command "async-shell-command")
      (setq shell-command-switch "-ic")
    (setq shell-command-switch "-c")
    )
  )

(add-hook 'minibuffer-setup-hook 'pre-command-hook-fn)

待办事项:修改 'exec-path' 以便让迷你缓冲区完成使用交互式 shell 的 PATH。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接