当我运行一个shell命令时,有没有办法让我的emacs识别我的bash别名和自定义函数?

38

在我的shell环境中,我有别名和自定义函数。当我在emacs实例中(我总是使用emacs -nw)执行shell命令(M-!),我无法使用它们。这很合理,因为我想象它启动自己的子shell来执行这些操作...但是是否有一种方法(也许在我的.emacs中)可以使这个工作?也许甚至涉及在执行任何shell命令之前默认引入一个环境?


1
它以非登录模式启动,您需要找到更改要运行的命令以启动shell并添加“-l”的位置。我使用vim,所以不确定emacs将其隐藏在哪里。 - Kevin
问题不在于登录,而在于交互。执行子命令 shell 是非交互式的(可以通过运行 M-x!tty -s 显示代码1来证明)。 - Nicolas Dudebout
可能是Emacs编译模式无法看到bash别名的重复问题。 - UpAndAdam
我也遇到过这个问题。但是,由于“M-&”及其在Dired中的特殊性,我放弃了,并将我的别名放入了“.zshenv”中。请参见我的答案以获取更多详细信息。 - GDP2
6个回答

44

以下是我对一个相关问题的评论:

我认为M-x shell-commandM-x compile都通过调用call-process在一个子 shell 中执行命令。请尝试在您的 .emacs 文件中添加以下代码(或者直接评估它):

(setq shell-file-name "bash")
(setq shell-command-switch "-ic")

我注意到在上述的评估之后,.bashrc 别名被用于 M-x shell-command 和 M-x compile,即:

M-x compile RET 你的别名 RET

应该就可以工作了。

我的环境:Emacs 24.1(预测试版本 rc1),OSX 10.7.3

来源


2
@PalaceChan: -i用于交互,而-c告诉bash读取其后的任何命令(因此Emacs在shell调用中使用了什么)。 - jmdeldin
2
@PalaceChan,鉴于你的下一个问题(https://dev59.com/8XDYa4cB1Zd3GeqPD78T?lq=1),询问为什么会出现错误,那么它是如何美妙地工作的呢? - UpAndAdam
2
(在终端中使用Emacs 24.4.1)这对我来说基本上是有效的,但我在输出之前收到消息:bash:无法设置终端进程组(-1):设备不当的ioctl bash:此shell中没有作业控制 - AAAfarmclub
1
这个不起作用 - 我正在运行emacs 26.1,bash 4.4。 - fbynite
对我很有帮助,改变了我的生活!现在运行的是GNU Emacs 25.3.50,之前是Aquamacs 3.5。 - Tom Swirly
显示剩余3条评论

3
我们需要在非交互式shell中启用别名扩展,最好只在从emacs调用它们时启用(以避免运行其他shell时造成微妙的差异)。对我有用的方法是创建两个文件:~/.alias包含所有我的别名,例如。"最初的回答"
alias python python27

and ~/.aliasExpand has

source ~/.alias
shopt -s expand_aliases

我当然也用``````替换了.bashrc文件中的所有别名。"最初的回答"
source ~/.alias

最终,我将以下内容添加到我的.emacs文件中:
(setenv "BASH_ENV" "~/.aliasExpand")

我尝试了Keith Flower的解决方案(使shell交互),但我得到了以下错误信息:

bash: 无法设置终端进程组(-1):不适当的ioctl设备
bash:此shell中没有作业控制

请注意,我是通过Glenn Jackman和Nicholas Dudebout的提示获得了这个错误。
如果您愿意冒所有shell拓展别名的风险,并且您不介意为每个emacs shell运行所有的.bashrc,那么您可以简化此操作,只需添加以下内容即可:
shopt -s expand_aliases

to your .bashrc and

(setenv "BASH_ENV" "~/.bashrc")

to your .emacs


1
谢谢您的回答。顺便说一下,我认为您可以直接使用 (setenv "BASH_ENV" (expand-file-name "~/.bashrc")) 或者 (setenv "BASH_ENV" (substitute-in-file-name "$HOME/.bashrc")),这样就不需要使用 shopt 命令了。 - fengqi

2
为了让shell-command按照https://dev59.com/nGct5IYBdhLWcg3wQ7Qy#12228646中描述的技术,在执行命令前读取~/.bashrc,而不会因为整个Emacs会话中定义了$BASH_ENV而产生潜在的副作用,请在您的~/.emacs.d/init.el(或.emacs)文件中尝试以下内容:
;; I want M-! (shell-command) to pick up my aliases and so run .bashrc:
(setq shell-file-name "bash-for-emacs.sh")  ; Does this: BASH_ENV="~/.bashrc" exec bash "$@"
(setq shell-command-switch "-c")

根据第二行的注释所述,在您的$PATH中安装一个名为bash-for-emacs.sh的脚本,其内容如下:

#!/bin/bash

BASH_ENV="~/.bashrc" exec bash "$@"

请注意,即使[ -z "$PS1" ]返回true(表示非交互式shell),您的~/.bashrc可能需要更改以定义非交互式别名。这是我为自己的环境采取的方法(虽然它很简单),我的环境在https://github.com/jcburley/UnixHome上可以找到。
此外,这假定您想将Bash用作由Emacs生成的shell,就像我一样。

2
请阅读 http://www.gnu.org/software/bash/manual/bashref.html#Bash-Startup-Files,了解有关bash启动文件的内容。
对于非交互式shell,仅会源化BASH_ENV环境变量的值。如果emacs将用于shell命令,则可以像这样调用:BASH_ENV=~/.bashrc emacs,但某些程序专门使用“/bin/sh”。请注意不要更改原有的HTML标签格式。

2
看起来你还需要使用 shopt -s expand_aliases 命令启用别名机制。这在非交互式 shell 中默认是未启用的。 - Nicolas Dudebout

1

如果您直接设置shell-command-switch,会使得shell-command明显变慢(如果您使用许多(ba|z)sh插件),因为它会被各种非交互式函数调用,例如shell-command-to-stringeshell-remote-command等,以及其他函数的众多调用,所有这些都不需要.bashrc.zshrc

例如,在我的机器上(也可能是您的机器):

(benchmark-elapse (let ((shell-command-switch "-c")) (shell-command "")))
0.005170422
(benchmark-elapse (let ((shell-command-switch "-ic")) (shell-command "")))
0.242628824
;; Empty ~/.zshrc: 0.168341049

因此,我们应该选择一种方式,只有在交互式调用shell-command时才使用交互式shell。
;;;###autoload
(defun my-shell-command-interactive-a (fn &rest args)
  "Use interactive shell for `shell-command' when invoked interactively.
Setting the \"-i\" switch all the time will significantly slow
down `shell-command' because there may too many files to source."
  (let ((shell-command-switch (if (called-interactively-p 'interactive)
                                  ;; Replace the first "-"
                                  (replace-regexp-in-string
                                   "\\(-\\).*\\'"
                                   "-i"
                                   shell-command-switch
                                   nil
                                   nil
                                   1)
                                shell-command-switch)))
    (apply fn args)))

(dolist (cmd '(shell-command async-shell-command)) 
   (advice-add cmd :around #'my-shell-command-interactive-a))

-3
将别名和函数放在.bashrc中,而不是.bash_profile中。后者仅在登录shell中执行,前者在所有shell中都会执行。

4
.bashrc 文件只会在交互式 shell 中被调用,而不是所有的 shell。参考链接:http://www.gnu.org/software/bash/manual/bashref.html#Bash-Startup-Files - glenn jackman
2
@Barmar,将别名放在.bashrc中并没有改变任何事情。 - Nicolas Dudebout

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