ctrl+z 不会将 htop 发送到后台

ctrl+z 不会将 htop 发送到后台

我在 macOS 12.4、Apple M1 上使用 zsh。

当我使用该命令正常运行 htophtop并使用它时ctrl+z,它会按预期运行并将进程发送到后台。我可以使用命令再次唤起它fg,然后使用它再次将其发送到后台ctrl+z

但是,当我运行 htop 并使用命令直接将其发送到后台时

htop &

并使用 唤起它fgctrl+z不再将其发送到后台。ctrl+z没有任何影响。

这是预期的吗?当我使用 时,我没有遇到同样的问题vim &

答案1

我可以在 Ubuntu 上使用htop以及其他一些基于 ncurses 的应用程序(例如mutt.

问题的根源在于,当 zsh 的行编辑器 (zle) 处于活动状态时,tty 设备规则中的所有 VQUIT、VSUSP、VDSUSP、VSWTCH、VLNEXT 特殊字符都被禁用,因此在按Ctrl+时Z,zle 会收到^Z一个系统尝试向前台进程组发送 SIGTSTP(VSUSP 设置)。

你可以看到那里在代码中。

当 zsh 离开行编辑器并运行命令(或将作业放回到前台)时,终端状态将恢复(包括恢复 SUSP,就像^Z之前一样)。

现在,当您启动htop &TUI 应用程序时,您会立即重新进入行编辑器(返回到提示符),同时htop在后台进行初始化。

htopncurses 应用程序通常会执行与 zle 相同的操作:它们检索初始 tty 设置,更改它们以适应自己的使用,并在退出(或暂停)时恢复保存的 tty 设置。

现在的问题是,当在后台启动时,ncurses 应用程序检索的初始 tty 设置是由 zle 设置的,而不是常规设置,因为当它们初始化时,您已经回到提示符处。因此,此时他们会看到 SUSP 被禁用。

当他们尝试更改设置(这会更改 SUSP 设置之外的其他内容)时,他们会因 SIGTTOU 而暂停,因为他们不在前台。

然后,当您fg执行此操作时,zsh 会在向应用程序发送 SIGCONT 之前将 tty 设置恢复为常规设置,但随后应用程序只是恢复其tcsetattr()在初始设置之上应用更改的设置,因此它们会重新应用禁用暂停。

如果我运行:

stty -a < /dev/pts/1

/dev/pts/1在我的例子中,ttyhtop已连接并已恢复)

我懂了:

intr = ^C; quit = <undef>; erase = ^?; kill = ^U; eof = ^D; eol = <undef>; eol2 = <undef>; swtch = <undef>; start = <undef>; stop = <undef>; susp = <undef>; rprnt = ^R; werase = ^W;
lnext = <undef>; discard = <undef>; min = 1; time = 0;

因此,并不是它htop不受 SIGTSTP 的影响或者htop没有正确地位于前台,而是在该终端上没有导致发送 SIGTSTP 的字符。

如果我开始htop为:

htop & sleep 1

然后,当htop检索初始设置时,您将不会返回提示符,因为sleep仍将运行,并且您会发现htop在使用 恢复后仍然可以暂停^Z

您将得到相同的行为,tcsh在其自己的行编辑器中禁用 SUSP,但不会在 bash 和其他使用 readline 的 shell 中禁用,也不会在我测试过的其他几个 shell 中禁用,这意味着它们无法^Z在自己的行编辑器中绑定。其中一些确实禁用了一些特殊设置。例如 bash 禁用 LNEXT(通常^V)。

相关内容