我正在尝试确定我正在运行的命令是否在 SSH 会话内。通常,通过检查$SSH_CONNECTION
或遍历进程树并查找可以很好地工作sshd
。
但是,如果我screen
在本地启动会话,然后通过 SSH 重新附加它,则这些都不起作用。
在重新附加的屏幕会话中是否有某种方法可以确定会话当前附加到哪个外壳?
进程树看起来像shell(X) --> screen(Y) --> systemd(1)
,这是有道理的,因为当我退出本地终端时,屏幕会话可能会重新设置父级。
screen -ls
没有说任何其他内容(Attached)
,仅包含 PID Y
,没有当前附加位置的有用 PID 。
它所附加的进程树shell(A)
包括一个子进程screen(B)
,但我找不到链接 PIDY
和 的方法B
。我什至试图找到屏幕使用的 unix 套接字的另一端,但它是空的。 (甚至检查为root
)。
难道这只是不可能的事情吗?
答案1
经过大量的实验,这就是我的最终结果:
找到 shell 正在运行的屏幕。继续遍历 pstree,直到找到屏幕进程:
screen_pid=$(pstree -psUA $$ | egrep -o 'screen\([0-9]+\)' | tail -1 | egrep -o '[0-9]+')
查看该进程的所有打开的文件。找到该列表中唯一的 /dev/pts/* 文件:
screen_pts=$(lsof -p $screen_pid | grep /dev/pts | awk '{print $NF}')
找到控制伪终端的屏幕进程:
ps -o pid=,tty= -C screen | grep ${screen_pts/\/dev\/} | awk '{print $1}'
从那里开始,父进程将是 shell/ssh/启动屏幕的任何内容现在附着在外壳上。
这里肯定有一些奇怪的假设“在我的机器上工作(tm)”,但这是一般的想法。
如果需要可靠性,使用stat
withst_rdev
将消除 hacky /dev/pts/5 -> pts/5 替换。类似的东西可以用来过滤打开文件的列表,其中major(st_rdev)
==一些代表伪终端的值。