我在 macOS 12.4、Apple M1 上使用 zsh。
当我使用该命令正常运行 htophtop
并使用它时ctrl+z
,它会按预期运行并将进程发送到后台。我可以使用命令再次唤起它fg
,然后使用它再次将其发送到后台ctrl+z
但是,当我运行 htop 并使用命令直接将其发送到后台时
htop &
并使用 唤起它fg
,ctrl+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
在后台进行初始化。
htop
ncurses 应用程序通常会执行与 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
)。