关于备用屏幕和后台暂停的使用,启动 less 与在 ZSH 中启动 cat 有何不同

How does launching `less` differ from launching `cat` in ZSH with regards to the usage of alternate screen and background suspension

在我的 OS 上,默认情况下,ZSH 有 -tostop(或者是 tty?)。

这允许后台进程在有输出时输出到 shell。

因此:

> stty -tostop
> echo 'random' >/tmp/random
> cat /tmp/random &
[1] 7588
random
[1]  + 7588 done       cat /tmp/random

对应:

> stty tostop
> echo 'random' >/tmp/random
> cat /tmp/random &
[1] 3888
[1]  + 3888 suspended (tty output)  cat /tmp/random

阅读文档并进行一些试验,我发现 ZSH 有 4 种类型的挂起进程(您可以使用 kill -$SIGNAL $PID ; jobs 查看):

job state              - signal that gives you job state
suspended              - SIGTSTP
suspended (signal)     - SIGSTOP
suspended (tty input)  - SIGTTIN
suspended (tty output) - SIGTTOU

这意味着 3888 进程正在接收 SIGTTOU 信号。

这一切都有道理。

现在我的问题是,为什么 less 不受 stty tostopstty -tostop 的影响?

> stty tostop
> less /tmp/random &
[1] 6300
[1]  + 6300 suspended (tty output)  less --LONG-PROMPT --chop-long-lines /tmp/random

> stty -tostop
> less /tmp/random &
[1] 4808
[1]  + 4808 suspended (tty output)  less --LONG-PROMPT --chop-long-lines /tmp/random

如您所见,在这两种情况下,less 总是在后台暂停。

现在,我知道 less -X,而且我还知道终端仿真器具有的备用屏幕功能。 事实上,您可以 运行 使用 less -X 执行上述 2 个命令,它会导致相同类型的暂停。 即使 -X 成功了不使用备用屏幕,less 仍然得到 suspended (tty output)!

我想知道 less 总是被 suspended (tty output) 暂停的实际机制,即使 tostop 被切换,甚至 -X也正在切换。 shell 怎么可能总是将 SIGTTOU 发送到 less,除非有其他方式 less 被暂停。

(你没有指定你的 OS,但这个答案是基于 linux)

使用 strace 你可以看到 stty 在 fd 0 (stdin) 上执行 ioctl 切换 termios 结构的 c_lflag 值中的一位。

strace 还显示 less 将打开 /dev/tty 并在其上发出 ioctl 以更改 c_lflag.

所以 less 在输出任何内容之前简单地做与 stty tostop 相同的事情。