我尝试运行以下命令:
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 进行读取,并接受来自它的命令。它不会从标准输入读取命令;那只是为了数据。
因此我们有两个准独立过程(cat
和less
)
独立(同时)在两个独立的文件描述符上从键盘(即 tty/终端)读取数据。这是一种令人困惑的情况,有点像“竞争条件”。我发现它有点类似于弹球机,其中有很多球可以走的球道或路径——并且它总是走一;它永远不能接受多个进程。类似地,当多个进程同时从同一终端读取时,输入的每一行(如果终端处于行模式)或输入的每个字符(如果终端处于字符模式)都只进入一个进程。选择是任意的,与弹球的动作不同。它不是完全“随机的”,就像进程的调度不是随机的一样;但它本质上是不可预测的。
因此,发生了以下事情:
cat
从它的标准输入(默认情况下是终端)读取,并写入它的标准输出(即到的管道)less
。- 在某个时候,
less
调用ttyname(1)
,获取所在终端的名称,并打开该终端进行读取。 less
从其标准输入(管道)读取一整屏数据(即 24 行或其他)并将其写入标准输出(终端)。- 然后,
less
发出:
提示,将终端置于字符模式,并开始读取从终端(不是来自标准输入)。 - 因此,我们现在有两个进程(
cat
和less
)同时从终端读取数据,弹球现象开始出现——您输入的字符(和/或行)将半随机地进入cat
或less
。如果进入cat
,它将被写入管道并将less
其视为数据。如果进入less
,它将被解释为less
命令。
这实际上与缓冲没有任何关系。