如果我这样做ls | less
,ls
会检测到它没有连接到终端,这很公平。除了那个less
是连接到终端。在此设置中,ls
可以生成针对终端的彩色和列化输出,并less
可以正确处理它。您可以使用 使颜色正常工作ls --color=force | less -r
,但这需要更多的打字,而且它不做列。
如果有一个开关可以less
告诉连接到它的任何东西,将其视为真正的终端,那就太酷了。因此,您可以ls | less -T
在 中获取彩色和列式列表less
。
有做过这样的事吗?
less
像它这样的寻呼机实际上可以自己做到这一点,还是需要外壳程序的配合?例如,shell 是否需要设置一个伪终端来ls
连接?
答案1
它是设置管道的外壳。less
不参与其中。
当您这样做时ls | less
,shell 会在创建最终将执行管道写入端的进程的标准输出和将执行同一管道的读取端的进程的标准输入后同时ls
启动。less
ls
less
ls
检测到其标准输出不是 tty 设备,并相应地改变其行为。less
对此我们无能为力。
什么是壳可以做的是使用伪终端对而不是管道来连接两个进程,但这将是一个坏主意,因为伪终端不是为此设计的。其一,断开连接会产生问题。less
如果它的标准输入是伪终端主机,可能会感到困惑。
ls
另一种方法是获得第三个进程,该进程通过伪终端对读取输出并less
通过管道将其输入,例如@JdeBPptyrun
或ptybandage
, 或expect
'sunbuffer
或 using zsh
'szpty
内置函数:
zmodload zsh/zpty
ttypager() { (zpty c "stty raw -echo; ${(q)@}"; zpty -r c) | less -RFX; }
ttypager ls
ls
将在新终端的新会话中运行,因此当您按 ^C 时不会收到 SIGINT,或者less
在完成写入之前退出时不会收到 SIGPIPE。然而,由于在这些情况下,持有主端(这里是子 shell)的进程仍然ls
会收到 SIGHUP 并死掉。
zpty
这里运行命令就像使用 一样eval
,因此别名将被扩展。实际上,即使您调用ttypager \ls
asttypager
仍会收到ls
参数并稍后执行别名扩展,它们也会被扩展。
另请注意,stdout 和 stderr 都会进入该伪终端并最终进入管道。
这仍然是一个肮脏的黑客行为。在这里,最简单的方法是告诉ls
其行为就像连接到终端一样。
您可以使用辅助函数,例如:
paged_ls() { ls -C --color=always "$@" | less -RFX; }
where-C
强制按列输出(ls
当输出到达终端时,包括 GNU 在内的某些实现默认执行此操作)并--color=always
强制以颜色输出,无论输出是否到达终端。
答案2
执行此操作的一般方法是使用 Bernstein 等工具ptybandage
:
$ptybandage ls > 摆动 ;更少的摆动
或者,在这种情况下更好,伯恩斯坦的ptyrun
:
$ptyrun ls |较少的
进一步阅读
- https://unix.stackexchange.com/a/249801/5132
- 丹尼尔·伯恩斯坦 (1996)。
ptyrun
。DJBwares。 - 丹尼尔·伯恩斯坦 (1996)。
ptybandage
。DJBwares。 - 乔纳森·德博因·波拉德 (2014)。
ptyrun
。小吃指南。软件。 - 乔纳森·德博因·波拉德 (2014)。
ptybandage
。小吃指南。软件。