我偶尔会使用镐功能来git
定位感兴趣的更改。显然,这可能非常慢(这同样适用于,比如说hg grep
),但更重要的是它是突发的:一些结果聚集在一起,由不活动分开。
出于这些原因,我尝试在结果出现时读取结果,实际上通过将输出管道传输到less
(事实上,这是git
默认情况下的操作):当突发到来时,您不可能ctrl-S
对软件流程足够快地击中控制功能现在很有用。
但我经常遇到这样一种行为:less
如果我滚动得足够多,即使只有一行要在屏幕上显示的内容还没有从命令中出来git
,less
就会陷入困境,我会失去它的提示和大多数控制它的方法,直到更多内容来了。现在,我明白为什么会发生这种情况,但是如果这是 shell 命令的行为,我会用来ctrl-Z
恢复提示(然后执行bg
)。是否有等效的方法less
来恢复寻呼机提示?
在这种情况下,ctrl-Z
没有用:Unix 作业控制不适合管理屏幕内容的命令。此外,无论如何我都不想回到 shell 提示符:通常,我想做的是检查我在反复按空格键时可能瞥见的内容,所以我不想留下更少的内容。
Ctrl-C
也是无用的:虽然它确实允许我恢复提示,但这还会导致收到的内容被冻结;也就是说,当我的好奇心得到满足并尝试返回到最新内容(按几下空格键或G
等)时,无论我等多久,都只会出现我所看到的内容。即使使用F
(tail -f
模式)。
我使用此命令来模拟git
行为:
(echo -e 'foo\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n.' ; sleep 3 ; echo -e 'bar\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n.' ; sleep 10; echo baz) | less
答案1
解决方案实际上是使用ctrl-C
,但同时确保生成的信号是不是发送到通过管道传送到 的其他命令less
。这是我最初未能获得的决定性见解:虽然仅从less
终端执行读取,因此普通输入仅适用于该命令,但另一方面,源自终端驱动程序的信号被分派到管道中的所有进程。
以这种方式控制信号调度说起来容易做起来难。据我所知,没有好的解决方案,因此我提出了最不坏的解决方案:用于将setsid(1)
其他命令隔离到它们自己的会话中:
% setsid sh -c "/bin/echo -e 'foo\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n.' ; sleep 3 ; /bin/echo -e 'bar\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n.' ; sleep 10; /bin/echo baz" sh-c | less
通过此设置,当我点击时,ctrl-C
我得到了预期的行为:less
提示出现在它之前可以收到的内容之后sleep
,我可以浏览回之前的所有内容,当我直接返回到最新内容时,最后一个内容( baz
,此处) 最终出现。通过将内容生成填充到其自己的会话中,我将该进程与信号隔离(我需要涉及该信号以中断读取操作,否则该读取操作将less
被卡住)。
主要问题是这setsid(1)
完全不标准;虽然所有 Unix 和类 Unix 内核都支持setsid(2)
系统调用,但它作为独立命令的可用性有点像 Linux 主义。如果它在您的安装中不可用,您最喜欢的包管理器应该提供它(源很简单并且位于公共领域),无论是单独提供还是作为包的一部分util-linux
:
% brew install util-linux # MacOS
不要被这个名字误导:setsid(1)
至少,它是可移植的。 (注意:util-linux
此处显示的 Homebrew 的 cask 仅包含 keg,即由于冲突,搜索路径中未安装任何内容;您必须手动将其 bin 目录添加到$PATH
)