tmux Kill-window 不会杀死子进程

Ale*_*lls 5 tmux

如果我这样做ctrl-c并且ctrl-d杀死窗格中的进程然后从 tmux 退出,那么所有子进程都会死亡。

但如果我这样做:

ctrl+b后接shift+%

然后选择 Y 杀死窗口,然后进程保持活动状态。知道如何确保窗口被杀死时进程也被杀死吗?

Kam*_*ski 5

Ctrl+ckill-window

使用Ctrl+c通常(当stty -a显示时intr = ^C)将 SIGINT 发送到前台进程组中的进程。您似乎假设任何获得 SIGINT 的进程都会退出(被杀死),但一般情况下可能不会。

您提到了Ctrl+ d,所以 tmux 服务器和您想要终止的进程之间可能存在一个交互式 shell。在这种情况下,SIGINT 被发送到进程,而不是 shell;但即使 shell 得到了它,它也不会退出。(我并不是说它总是这样;我是说它符合你的描述)。

因此,在Ctrl+进程终止后c,您可以按Ctrl+d退出 shell。

当您在 tmux 中终止一个窗口时,相应的伪终端将关闭,并且使用它们作为控制终端的进程会收到 SIGHUP。这样的进程可能会向其子进程发送 SIGHUP (对于 shell,请参阅此答案)。进程可能会忽略该信号(请参阅参考资料nohup)。即使它忽略该信号,如果它尝试使用不再存在的伪终端,它也可能(或可能不会)稍后死亡。

简而言之:

  • 您向相关进程发送 SIGINT 或 SIGHUP;
  • 是否以及如何对 SIGINT 或 SIGHUP 做出反应取决于进程

发送 SIGINT

进程可能会忽略 SIGINT。如果Ctrl+c为您正在处理的进程执行您想要的操作,那么也许在杀死窗口并发送 SIGHUP 之前向它们发送 SIGINT 就足够了;就像您在每个窗格中点击Ctrl+一样c

以下命令在当前窗口的窗格中列出进程(tmux 服务器的直接子进程),获取各自的前台进程组并向每个进程发送 SIGINT:

tmux list-panes -F "#{pane_pid}" | xargs ps -o tpgid= | xargs -I{} kill -s SIGINT -{}
Run Code Online (Sandbox Code Playgroud)

问题是这个管道也将收到 SIGINT,并且可能会提前终止。为了解决这个问题

  • 从其他地方运行命令并使用-t指定窗口,
  • 或者实现一些逻辑,因此排除管道的前台进程组,
  • 或在后台运行管道:

    tmux list-panes -F "#{pane_pid}" | xargs ps -o tpgid= | xargs -I{} kill -s SIGINT -{} &
    
    Run Code Online (Sandbox Code Playgroud)
  • 或使命令忽略信号:

    sh -c '
    trap "" SIGINT
    tmux list-panes -F "#{pane_pid}" | xargs ps -o tpgid= | xargs -I{} kill -s SIGINT -{}
    '
    
    Run Code Online (Sandbox Code Playgroud)

我认为这种方法很容易出现竞争条件;事情可能会在ps和之间发生变化kill。更好的(?)替代方法是将Ctrl+发送c到每个窗格:

tmux list-panes -F "#{pane_id}" | xargs -I {} tmux send-keys -t {} C-c &
Run Code Online (Sandbox Code Playgroud)

使用此钩子使 tmux向即将编辑的窗口中的每个窗格发送Ctrl+ :ckill-window

tmux set-hook before-kill-window 'run-shell "
   tmux list-panes -t \"#{window_id}\" -F \"##{pane_id}\" | xargs -I {} tmux send-keys -t {} C-c
"'
Run Code Online (Sandbox Code Playgroud)

这看起来很糟糕,因为存在三个级别的引用,但它似乎在我的测试中仍然有效(尽管我还没有彻底测试)。的目的##是推迟 的扩展#{pane_id}。要点是工作#{window_id}时需要扩展run-shell,但必须生存并且只有在生成输出#{pane_id}时才扩展。list-panes

注意钩子覆盖kill-window但不是kill-pane,kill-sessionkill-server。也kill-window不仅仅是重复几次,所以当一个窗格被强行破坏时 钩子肯定不会覆盖所有情况。还有和命令。kill-panebefore-kill-panerespawn-pane -krespawn-window -k


如果还不够怎么办?

进程可能不会在 SIGINT 时终止。作为tmux list-panes -F "#{pane_pid}"起点,您可以尝试获取要向其发送 SIGTERM(甚至 SIGKILL)的 PI​​D(和/或 PGID)列表。这种一般方法的主要问题是它可能会产生一个进程并完全断开它与其祖先和 tty 的连接。

因此,通常您可能无法跟踪源自给定 tmux 窗口的所有进程。