为什么执行“emacs --daemon”后,emacsclient找不到socket?

14

当在bash中执行emacs --daemon后,emacsclient说找不到socket,这让人非常困惑:

$ ps aux | grep emacs
shiangro         1744   0.0  0.0  2432784    604 s000  S+    1:03下午   0:00.00 grep emacs
$ /usr/local/bin/emacs --daemon
("emacs")
Starting Emacs daemon.
Restarting server
$ /usr/local/bin/emacsclient -t
emacsclient: can't find socket; have you started the server?
To start the server in Emacs, type "M-x server-start".
emacsclient: No socket or alternate editor.  Please use:

    --socket-name
    --server-file      (or environment variable EMACS_SERVER_FILE)
    --alternate-editor (or environment variable ALTERNATE_EDITOR)

我在我的.emacs文件中有以下设置:

(server-start)
(setq server-socket-dir "~/.emacs.d/server")

并且它可以工作,服务器文件~/.emacs.d/server/server就在那里,但是emacsclient却说找不到套接字,这让我很烦恼,因此我不得不使用-s选项告诉它套接字文件的位置。
当我想让emacs在每次重启(启动)系统后作为守护进程运行时,我发现了这个棘手的问题,我使用了crontab的◎reboot特殊字符串。
在这种情况下,cron成功地启动了emacs服务器,并且服务器文件~/.emacs.d/server/server也在那里,但是后来当我启动终端并尝试使用emacsclient -t时,它失败了并抱怨找不到套接字文件!
虽然我可以通过在每次执行emacsclient时使用-s ~/.emacs.d/server/server来绕过这个问题,或者将emacsclient别名设置为emacsclient -s ~/.emacs.d/server/server,但是否有更好的方法来安慰我的内心呢?
背景:
系统:Mac OS X 10.9.2
emacs:由homebrew安装的GNU Emacs 24.3.1

2
你期望emacsclient自动知道一个仅存在于你希望连接的Emacs服务器中的值!最简单的方法是不要更改“server-socket-dir”。如果你确实更改了它,那么告诉emacsclient也是很自然的事情。 - phils
是的,你说得对,谢谢! - sage han
5个回答

16

找到服务器套接字文件有点棘手,您可以使用lsof来找到它,然后再用一点grep来提取套接字路径/文件名。

lsof -c emacs | grep server | grep -E -o '[^[:blank:]]*$'

在OSX上,如果您希望运行的是/Application/Emacs,则需要使用-c Emacs更改lsof正在查找的命令名称。即:
lsof -c Emacs | grep server | grep -E -o '[^[:blank:]]*$'

您可以使用 cut 代替混乱的过滤器 grep(搜索非空格字符直到行末 [^[:blank:]]*$)。
lsof -c Emacs | grep server | cut -c70-

最好的方法是压缩间距并使用cut的字段切割。
lsof -c Emacs | grep server | tr -s " " | cut -d' ' -f8

现在你已经有了套接字(或者它是空的),你可以对emacsclient进行条件启动,例如:

#!/bin/bash 

socket_file=$(lsof -c Emacs | grep server | tr -s " " | cut -d' ' -f8)

if [[ $socket_file == "" ]]; then        
    # Just run Emacs (with any arguments passed to the script)
    # It would be a good idea to parse the arguments and clean/remove
    # anything emacsclient specific. 
    # (ie. -e should be --eval for emacs)
    # note that emacsclient doesn't fix these args for you either
    # when using -a / --alternate-editor

    emacs $@ &

    # or on OSX

    /Application/Emacs.app/Contents/MacOS/Emacs $@ &

else

    emacsclient $@ -n -s $socket_file

fi

如果在2017年它是/Application/Emacs.app/Contents/MacOS/Emacs,如果有更改请提交编辑。 - ocodo
这回答了问题。它明确要求MacOS / OSX帮助。 - ocodo
有可能将Emacs别名为emac。如果后台运行了多个守护进程,lsof可能会返回多个ID,这可能导致emacsclient $@ -n -s $socket_file失败。 - alper
@alper 谢谢,这听起来是可能的。我对Emacs和Macos的最新变化不是很了解。 - ocodo
有趣的是,如果有多个守护进程,$(lsof -c Emacs | grep server | tr -s " " | cut -d' ' -f8) 对于每个守护进程返回相同的值。也许可以通过使用head -n1来捕获第一个值进行解析。 - alper
显示剩余4条评论

11

自从你完成了:

/usr/local/bin/emacs --daemon

服务器已经启动。因此,实际上您不需要:

(server-start)
(setq server-socket-dir "~/.emacs.d/server")

在你的.emacs文件中执行该方法,这样服务器将被放置在 /tmp/emacs502(或者其他一些数字)路径下。在Linux系统中,emacsclient似乎没有问题地在该路径下找到它(在我的情况下是/tmp/emacs1920),因此 "emacsclient -nw" 命令可以正常使用。我正在尝试在使用HomeBrew安装的OSX上进行连接,发现我需要使用以下命令:

emacsclient -nw -s /tmp/emacs502/server

(如果您使用了--deamon=name,则在最后一行中使用"name"而不是"server")


10
可能的原因是你正在使用 Mac OS X 自带的 emacsclient(版本为 22),它找不到 Emacs 24。请检查你的 $PATH 是否像这样:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:,因为为了让 Homebrew 的符号链接起作用,/usr/local/bin 必须放在 /usr/bin 之前。 - dcorking
谢谢dcorking - 那正是我的问题!我已经删除了原始的emacs并安装了一个新的homebrew版本。还需要删除emacsclient。 - WuTheFWasThat
@WuTheFWasThat - 不需要删除默认的emacs。只需正确设置路径,首先查找homebrew目录即可。(我想那是/usr/local,如果我没记错的话。) - Diagon
类似的问题,细节稍有不同:我正在启动/Application/Emacs.app,而我的路径中的emacsclients按顺序是/usr/bin/emacsclient /Applications/Emacs.app/Contents/MacOS/bin-x86_64-10_9/emacsclient。这很烦人,因为我不想将/Applications/Emacs.app/Contents/MacOS/bin*添加到我的路径中-那样就不对了。应用程序应该是自相容的。 - Krazy Glew

3

如果我从命令行运行emacs,则emacsclient可以找到emacs服务器。但是,如果我从Ubuntu启动器中运行emacs,则emacsclient无法连接到服务器。

如果您想使用Emacs守护进程而不是服务器,请定义以下两个环境变量:

export ALTERNATE_EDITOR="" export EDITOR=emacsclient

您可以将这些环境变量添加到~/.bashrc~/.profile中。

如果ALTERNATE_EDITOR环境变量为空,则Emacs将运行其守护进程并连接到它。


这似乎是一个愚蠢的解决方案,但它是最直接的实现方式,并且在macOS(将变量设置为emacsclient的完整路径)和FreeBSD上都可以工作。 - rfinz

1
我认为emacsclient只能在标准路径中寻找特殊文件server,例如在/tmp/emacs1000中。 如果您更改了此参数的值server-socket-dir,则应该通过键-s告知emacsclient

有没有办法在Mac和Linux上指定相同的服务器套接字目录? - Dzung Nguyen
@nXqd 请尝试在 .bashrc 中设置环境变量 EMACS_SERVER_FILE。 - netawater

0
在 macOS 上,emacs 的 socket 名称计算如下:
export EMACS_SOCKET_NAME="${TMPDIR}/emacs$(id -u)/server"

根据emacsclient的说法,环境变量EMACS_SOCKET_NAME可以被设置来覆盖默认值。然而,在Homebrew环境中似乎不起作用。我在我的.bashrc文件中有这个设置,对我来说有效。
export EDITOR="emacsclient --tty"
export ALTERNATE_EDITOR="emacs --no-window-system"

case "$(uname -s)" in
    # ...

    Darwin*)
        export EMACS_SOCKET_NAME="${TMPDIR}/emacs$(id -u)/server"
        export EDITOR="${EDITOR} --socket-name ${EMACS_SOCKET_NAME}"
    ;;
esac

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