少:通过管道宣传 terminfo

Eri*_*mbs 0 pager pty terminfo

如果我这样做ls | lessls检测到它没有连接到终端,这很公平。不同之处在于less 连接到终端。在此设置中,ls可以生成彩色和列化输出目标终端,并less可以正确处理它。您可以使用 使颜色正常工作ls --color=force | less -r,但这需要更多的输入,而且它不处理列。

如果有一个开关less可以告诉连接到它的任何东西将其视为真正的终端,那就太酷了。因此,您可以ls | less -Tless.

  1. 有没有做过这样的事情?

  2. 或者less像它这样的寻呼机真的可以自己做到这一点,还是需要 shell 的合作?例如,shell 是否需要设置一个伪终端ls来连接?

Sté*_*las 5

它是设置管道的外壳。less不参与其中。

当你这样做ls | less时,外壳程序启动lsless同时后作出的过程中,最终将执行的标准输出ls管道的书写端和一个将要执行的标准输入less同一管道的读取结束。

ls检测到它的 stdout 不是一个 tty 设备,并相应地改变它的行为。没有什么less可以做的。

什么可以做的是使用一个伪终端,而不是对管道的两个进程联系起来,但是这将是一个糟糕的主意,因为伪终端的设计并不适合这一点。一方面,断开连接会出现问题。less如果它的 stdin 是伪终端主机,可能会感到困惑。

另一种方法是获得第三个进程,该进程读取lsvia 伪终端对的输出,并less通过管道将其提供给@JdeBP's ptyrunorptybandage, or expect'sunbuffer或 using zsh'szpty内置:

zmodload zsh/zpty
ttypager() { (zpty c "stty raw -echo; ${(q)@}"; zpty -r c) | less -RFX; }

ttypager ls
Run Code Online (Sandbox Code Playgroud)

ls将在新终端中的新会话中运行,因此当您按 ^C 时不会收到 SIGINT,或者less在完成写入之前退出时不会收到 SIGPIPE 。但是,由于持有主端(此处为子shell)的进程在这些情况下仍然ls会收到 SIGHUP 并死亡。

zpty这里运行命令就像使用一样eval,所以别名将被扩展。实际上,即使您调用ttypager \lsasttypager仍然会ls作为参数接收并稍后执行别名扩展,它们也会被扩展。

另请注意, stdout 和 stderr 都将进入该伪终端并最终进入管道。

这仍然是一个肮脏的黑客。在这里,最简单的方法是ls让它表现得好像它连接到终端一样。

您可以使用辅助函数,例如:

paged_ls() { ls -C --color=always "$@" | less -RFX; }
Run Code Online (Sandbox Code Playgroud)

Where-C强制列中的输出(包括 GNU 在内的某些实现ls在输出到终端时默认情况下会这样做)并--color=always强制以彩色输出,无论输出是否到终端。