`cat | less` 的行为是什么?

`cat | less` 的行为是什么?

我尝试运行以下命令:

cat | less

我知道这两个命令都需要标准输入。当我运行它时,这正是我所期望的:我的所有输入都转到 cat,而我无法向 less 发送命令(最终无法使用命令 . 退出程序q)。

事实并非如此。实际上,只要标准输入中发送的行数小于屏幕的行数,它就可以正常工作。当标准输入中发送的行数大于我的控制台的行数时,就会出现奇怪的行为。似乎输入有时会发送到cat,有时会发送到less。例如,意外的是,字母q 有时让程序退出。

为什么会出现这种我(天真地)没有想到的行为?

答案1

CAT 将接受来自 stdin 的输入(尽管可以说它更倾向于从文件或管道输入),并将其输出到 STDOUT

这意味着输入只是通过 cat 管道传输,然后直接传送到 less。这样你就可以在 less 中看到输出。

您最有可能感到困惑的是缓冲。CAT 正在缓冲输入,并在将其发送到 less 进行格式化时对其进行批处理(或等待文件结束)。

答案2

我讨厌自己这么说,但是

给 皮肤 贴肤的方法不止一种cat

我的意思是,有标准输入,然后有标准输入。或者,有从键盘(终端)读取,然后有从键盘读取。尝试

less < afilename

它的工作原理就像

less afilename

这意味着less除了从标准输入读取之外,还必须有某种方式从键盘读取。下面是另一个可以工作的命令,尽管您可能不期望它能工作:

less afilename < /dev/null

看着命令tty。它报告连接到标准输入的 tty(终端)的名称。它的工作原理是调用ttyname函数 带有一个参数0(标准输入的文件描述符)。

less可能正在调用ttyname(1) 以获取连接到标准输出的 tty(终端)的名称。然后它打开该 tty 进行读取,并接受来自它的命令。它不会从标准输入读取命令;那只是为了数据。

因此我们有两个准独立过程(catless独立(同时)在两个独立的文件描述符上从键盘(即 tty/终端)读取数据。这是一种令人困惑的情况,有点像“竞争条件”。我发现它有点类似于弹球机,其中有很多球可以走的球道或路径——并且它总是走;它永远不能接受多个进程。类似地,当多个进程同时从同一终端读取时,输入的每一行(如果终端处于行模式)或输入的每个字符(如果终端处于字符模式)都只进入一个进程。选择是任意的,与弹球的动作不同。它不是完全“随机的”,就像进程的调度不是随机的一样;但它本质上是不可预测的。

因此,发生了以下事情:

  • cat从它的标准输入(默认情况下是终端)读取,并写入它的标准输出(即到的管道)less
  • 在某个时候,less调用ttyname(1),获取所在终端的名称,并打开该终端进行读取。
  • less从其标准输入(管道)读取一整屏数据(即 24 行或其他)并将其写入标准输出(终端)。
  • 然后,less发出:提示,将终端置于字符模式,并开始读取从终端不是来自标准输入)。
  • 因此,我们现在有两个进程(catless)同时从终端读取数据,弹球现象开始出现——您输入的字符(和/或行)将半随机地进入catless。如果进入cat,它将被写入管道并将less其视为数据。如果进入less,它将被解释为less命令。

这实际上与缓冲没有任何关系。

相关内容