gunzip < 100terabytes.txt.gz | less
less(1)
根据需要读取尽可能多的行以填满屏幕,然后停止read(2)
。结果,当管道变满时,gunzip(1)
就会被堵塞。write(2)
当您向下滚动时,会一次又一次地less(1)
发出问题read(2)
,并且当管道被消耗时,gunzip(1)
允许发出write(2)
。您可以在这里来回完全灵活(假设gunzip < 100terabytes.txt.gz
未完成。)
到目前为止一切都很好。
less(1)
您可以使用开始文本搜索/
。但是,当在 中找不到搜索字符串时100terabytes.txt
,less(1)
基本上变得无响应。您可以使用 终止搜索Ctrl-C
。但gunzip(1)
它似乎关闭了和之间的管道less(1)
。我不喜欢这个。我想gunzip(1)
在放弃文本搜索后手动向下滚动以消耗更多行。这可能吗?
我是不是寻求建议,例如gunzip < 100terabytes.txt.gz | grep pattern | less
更新
你可以尝试一下od -v /dev/zero | less
答案1
当你按下 时Ctrl+C,这就是整个外壳工作(进程组)接收 SIGINT,less
拦截它以中止搜索,但gunzip
会终止。为了避免这种情况,你可以这样做:
(trap '' INT; gunzip < file.gz) | less
这样就忽略了 SIGINT,但请注意,此后gunzip
您将无法再中断。gunzip
对于gunzip
,这可能没问题,因为您需要做的就是退出,下次它写入某些内容时就会因 SIGPIPE 而死亡,但对于只是挂起而不输出某些内容的应用程序,这将是一个更大的问题(您仍然less
会不过gunzip
可以用于Ctrl+ZSIGTSTP 或Ctrl+\SIGQUIT)。
另请注意,某些命令例如pv
或ping
安装它们自己的 SIGINT 处理程序,这将恢复我们的trap '' INT
.
您可以创建一个函数来保存输入,例如:
iless() {
(trap '' INT; "$@") | less
}
iless gunzip < file.gz
或者:
noint() (trap '' INT; "$@")
noint gunzip < file.gz | less
但请注意,对于:
gunzip < file.gz | grep foo | less
你需要写它:
noint gunzip < file.gz | notint grep foo | less
或者:
noint eval 'gunzip < file.gz | grep foo' | less
或者:
iless eval 'gunzip < file.gz | grep foo'
另一种方法是使用进程替换:
less -f <(gunzip < file.gz | grep foo)
或(尽管不在 中zsh
):
less < <(gunzip < file.gz | grep foo)
在这些情况下,shell 不会在前台进程组中的进程替换中包含命令(除了 for 的第二种情况zsh
)。它们的进程组与 shell 的进程组相同。这意味着当您按 时他们不会收到 SIGINT Ctrl+C。
请注意,这些进程不会受到Ctrl+Z或Ctrl+\的影响。
在zsh
、ksh93
和中进行了测试bash
。
答案2
不是确切的答案,但它可能会解决您的问题。从man less
:
ESC-F Like F, but as soon as a line is found which matches the last
search pattern, the terminal bell is rung and forward scrolling
stops.
这可以被中断,^C
但我不知道它是否会破坏管道,因为我无法重现你的问题(我认为需要一个非常大的输入文件来测试这一点)。我认为它不会破坏管道,因为通常您可以在不断增长的文件上重复执行F
此操作,并且仍然有效(您仍然看到文件不断增长)。^C
F
问题是:less
如果没有找到模式,如何输入“最后搜索的模式”而不冻结?也许^K
选项/
会有所帮助:
^K Highlight any text which matches the pattern on the cur-
rent screen, but don't move to the first match (KEEP cur-
rent position).
编辑:或者更简单地说,用于?
“设置”此“最后搜索模式”。