我在远程工作站上运行了几个 Emacs (v21.2.1) 实例,我想通过 终止其中一个实例ssh
。我可以在 ssh 进入工作站时获取每个实例的 PID(pgrep emacs
例如,使用 ),但我不知道如何确定哪个进程打开了特定文件。
lsof
没有返回任何明显有用的信息,大概是因为 Emacs 在缓冲区中编辑文件时不会保持文件打开。也许可以将现有的 Emacs 窗口导出到我当前的位置,但我不知道该怎么做。
我是不是太愚蠢了,竟然认为这是可能的?
答案1
使用strace
查看它打开了哪些文件(它确实保持打开状态,或者至少经常检查文件)。这应该会为您提供该进程正在查看的所有内容的列表,显然您必须对其进行一些解析并过滤掉重复项(并替换正确的 pid):
strace -p1337 -e trace=file
它生成如下输出:
unlink("/tmp/emacsBYJwbf") = 0
stat("/home/tjackson/.jabber-avatars", {st_mode=S_IFDIR|0755, st_size=16384, ...}) = 0
stat("/home/tjackson/.jabber-avatars/e7e63a04ac20783855bc31ab8fcfb7bc23a39036.jpg", {st_mode=S_IFREG|0644, st_size=2556, ...}) = 0
stat("/lab_scratch/mymachine/work/path/to/some/file.cxx", {st_mode=S_IFREG|0644, st_size=45772, ...}) = 0
open("/lab_scratch/mymachine/work/path/to/some/file.cxx", O_RDONLY) = 10
stat("/lab_scratch/mymachine/work/path/to/some/file.cxx", {st_mode=S_IFREG|0644, st_size=45772, ...}) = 0
stat("/lab_scratch/mymachine/work/some/other/path/different/header_file.h", {st_mode=S_IFREG|0644, st_size=92260, ...}) = 0
open("/lab_scratch/mymachine/work/some/other/path/different/header_file.h", O_RDONLY) = 10
stat("/lab_scratch/mymachine/work/some/other/path/different/header_file.h", {st_mode=S_IFREG|0644, st_size=92260, ...}) = 0
stat("/home/tjackson/News/drafts/drafts/272", 0x7fbfffd400) = -1 ENOENT (No such file or directory)
stat("/scratch2/complex/tmp/output.log", {st_mode=S_IFREG|0644, st_size=378306, ...}) = 0
open("/scratch2/complex/tmp/output.log", O_RDONLY) = 10
stat("/scratch2/complex/tmp/output.log", {st_mode=S_IFREG|0644, st_size=378306, ...}) = 0
stat("/home/tjackson/.diary", {st_mode=S_IFREG|0644, st_size=72457, ...}) = 0
open("/home/tjackson/.diary", O_RDONLY) = 10
stat("/home/tjackson/.diary", {st_mode=S_IFREG|0644, st_size=72457, ...}) = 0
stat("/home/tjackson/News/drafts/drafts/271", 0x7fbfffd400) = -1 ENOENT (No such file or directory)
stat("/home/tjackson/News/drafts/drafts/273", 0x7fbfffd400) = -1 ENOENT (No such file or directory)
stat("/home/tjackson/personal/.newsrc-dribble", 0x7fbfffd400) = -1 ENOENT (No such file or directory)
stat("/lab_scratch/mymachine/work/sandbox/TAGS", {st_mode=S_IFREG|0644, st_size=2578671, ...}) = 0
open("/lab_scratch/mymachine/work/sandbox/TAGS", O_RDONLY) = 10
stat("/lab_scratch/mymachine/work/sandbox/TAGS", {st_mode=S_IFREG|0644, st_size=2578671, ...}) = 0
答案2
如果你正在跑步格努塞夫(XEmacs 服务器的 GNU Emacs 端口),或者如果您在 GNU Emacs ≥23 上运行包含的 emacsserver,则可以在正在运行的 Emacs 实例中运行任意 Lisp 命令。
gnuclient -r /tmp/gsrvdir1234/gsrv -batch -eval '(buffer-list)'
emacsclient -r /tmp/emacs1234/server -e '(buffer-list)' # Emacs ≥23 only
否则,我只能想到两种非常黑客的方法。
- 在 Emacs 实例的内存中搜索文件名。在 Linux 上,进程的映射内存位于
/proc/$pid/mem
,但您只能读取实际映射的页面,即通过 读取的页面/proc/$pid/maps
。我不知道是否有现成的程序可以做到这一点。 - 打开包含易受攻击的文件局部变量声明,即允许执行任意 Lisp 代码的变量。除非另有说明,否则 Emacs 21 仍将局部变量视为安全变量,因此肯定存在一些应该声明为有风险但实际上并未声明的变量。不过我不知道有任何例子。