Bash

如何將輸入結束信號發送到“read -N”?

  • February 13, 2017

如果我Ctrl+D使用read -N 1inbashksh93.

我知道傳輸結束字元和文件結束條件之間的區別,並且我知道Ctrl+D不使用時會read發生什麼-N(它發送 EOT,如果輸入為空,則底層read()返回零,發出信號EOF)。

但我不確定為什麼嘗試讀取特定數量的字元會如此徹底地改變這種行為。我本來預計會出現 EOF 條件,並且會退出以下循環:

while read -N 1 ch; do
 printf '%s' "$ch" | od
done

按下時輸出Ctrl+D

0000000 **000004**
0000001

bash手冊說read -Nksh93有類似的措辭):

-N nchars; read 在準確讀取nchars字元後返回,而不是等待完整的輸入行,除非遇到 EOF或讀取超時。

…但它沒有說明將 TTY 切換到原始/無緩沖模式(這是我假設正在發生的)。

-n選項 toread似乎對 的工作方式相同,Ctrl+D並且要讀取的字元數似乎也不重要。

我如何發出輸入結束信號read -N並退出循環(除了測試讀取的值),為什麼這與“裸”不同read

如果文件指出沒有 ASCII EOF 之類的東西,^D 的 ASCII 語義是 EOT,這可能會更有幫助,這是終端驅動程序在規範模式下提供的:它結束目前傳輸,read. 程序將 0 長度讀取解釋為 EOF,因為這就是 EOF 在具有它的文件上的樣子,但是終端驅動程序拒絕提供字元程式碼 4 而是吞下它並終止讀取並不總是您想要的。

這就是這裡發生的事情:控製字元語義是規範模式的一部分,終端驅動程序在這種模式下進行緩衝,直到它看到約定賦予其特殊含義的字元。stty -aEOT、BS、CR和許多其他人都是如此(請參閱man termios所有血腥細節)。

read -N是一個明確的命令,只傳遞接下來的 N 個字元。為此,shell 必須停止向終端驅動程序詢問規範語義。

順便說一句,EOF 實際上並不是終端可以設置或輸入的條件。

如果您繼續閱讀過去的 eof 其他任何內容,您將繼續獲得 EOF 指示符,但是終端驅動程序可以提供的唯一 EOF 是假的——想想看——如果終端驅動程序確實提供了真正的 EOF,那麼 shell之後也無法繼續閱讀它。都是同一個終端。這裡:

#include <unistd.h>
#include <stdio.h>
char s[32];
int main(int c, char**v)
{
   do {
       c=read(0,s,sizeof s);
       printf("%d,%.*s\n",c,c,s);
   } while (c>=0);
}

在終端上嘗試一下,您會看到規範模式下的終端驅動程序只是解釋 EOT 以完成任何未完成的讀取,並且它在內部進行緩衝,直到它看到一些規範的輸入終止符,而不管讀取緩衝區的大小(鍵入長於 32 的行字節)。

讓你困惑的文字¸

除非遇到 EOF

指的是真正的EOF。

引用自:https://unix.stackexchange.com/questions/339674