我正在尝试确定我正在运行的命令是否在 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
)。
这只是不可能的事情吗?
经过大量的实验,这就是我最终得到的结果:
找到运行 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/whatever 启动的屏幕,现在附加到 shell。
这里肯定有一些“在我的机器(tm)上工作”的骇人听闻的假设,但这是一般的想法。
如果需要可靠性,使用
stat
withst_rdev
将消除 hacky /dev/pts/5 -> pts/5 替换。类似的东西可以用来过滤打开文件的列表,其中major(st_rdev)
== 一些代表伪终端的值。