如何在 bash 中可视化 EOF

如何在 bash 中可视化 EOF

/dev/null是一个特殊的 Linux 文件,它会丢弃写入其中的所有内容,并EOF在读取时提供。

我想通过阅读/dev/null来获得并形象化这一点EOF。如果我尝试:

$ cat /dev/null | hexdump

这不起作用。返回提示符但没有任何输出。EOF甚至没有 ASCII 代码,所以也许这就是原因。

  1. 还能EOF算人物吗?

  2. EOF当 bash 中提供时,有没有办法检测和打印stdin

就像是:

$ cat /dev/null | some_tool
EOF

我在 Ubuntu 20.04.3 上使用GNU bash, version 5.0.17(1)-release (x86_64-pc-linux-gnu),但我希望解决方案(如果有)与这些特定版本无关。


这是不是作业,但只是了解更多信息的一种方式EOF

答案1

尽管在原始 ASCII 控制字符集中定义了一系列“End of {something}”字符,但 EOF 不是字符。 EOF 是一种可以检测到的情况,因为无法从输入流中读取更多内容。

例如,这个循环将持续下去,直到没有更多内容可读(即已达到 EOF)

{
  while IFS= read -r line; do
    printf '%s\n' "Read: >> $line <<"
  done
  if [ -n "$line" ]; then
    printf '%s\n' "And some extra data after the last line: >> $line <<"
  fi
  echo 'No more'
}

或者更有效(在某些实现中也不会阻塞 NUL 字节sed),完全避免 shell 循环

LC_ALL=C sed 's/.*/Read: >> & <</'; echo 'No more'

(如果最后一行之后有数据,则将其作为该No more行的前缀)。

终端的默认设置是,^D当您按下时,终端发送的字符Ctrl D由终端驱动程序解释为表示 EOF。不过,它不会将该(或其他)字符发送到应用程序;它导致read()tty 设备文件上的 s 返回任何要读取的内容,如果没有任何内容,则应用程序将其解释为 EOF(查看stty -a并查找eof终端设备当前的 EOF 字符是什么)。实现自己的行编辑器的 shell 或其他应用程序通常以相同的方式处理该字符(至少在空行缓冲区上时)。

答案2

您得到的/dev/null只是read()系统调用成功返回并读取零字节。这与尝试从文件结尾(或之后)开始时发生的情况相同read(),因此,它被称为“文件结尾”。

但也存在更奇怪的情况,例如终端,它可以在一次调用中返回零字节(如果用户点击^D空行,或在另一次调用之后^D),但然后在下一次读取时返回更多数据。还有数据报套接字,可能支持零字节数据报,系统将为此类数据报返回零字节,但在下次调用时仍返回下一个数据报。当然,您也可以read()从末尾的文件中获取零字节,但稍后再次尝试调用,这次会发现更多数据在等待。 (这就是 的实现tail -f可能会做的事情。)

您无法真正“打印 EOF”,因为没有任何内容可打印。只是缺乏数据而已。

知道cat退出于 EOF,你当然可以做类似的事情

(cat /dev/null; echo EOF) | whatever...

在结束后打印一些内容。在我看来,这不是很有用。

看:

答案3

/dev/null不发送EOF。它只是断开连接。它关闭文件。它模拟零长度的文件。

答案4

从逻辑上讲,EOF 的概念是由 I/O 处理程序生成的。 EOF 信号通常与正在处理的数据无关。

“发送 EOF”的唯一方法是让读取器报告没有任何内容可读取,以响应读取某些内容的请求。

考虑以下代码,其中函数 Hi 中继 stdin 直到 EOF,并用于重放 echo 命令的输出:

Hi() {
  while IFS= read -r -d $'\n' || [[ "$REPLY" ]]; do
    echo "Hi: $REPLY"
 done }
Hi < <(echo Hello)
Hi: Hello
  • <(command) 使 bash 根据所提供命令的输出创建一个管道(概念上是一个文件)。
  • <(command) 将其自身替换为管道的唯一文件名,如果您说:
echo <(echo Hi)
/dev/fd/63

因此,<(command) 从其 stdout 创建一个文件,并且每个文件可能有一个逻辑 EOF,其中读取器知道由于数据的物理结尾而不再有可用数据。

只要 <() 内的命令仍在执行,管道就会保持打开状态,从而保持管道打开。当<(命令)完成时,管道的输入端被关闭。

当 bash read 语句看到 EOF 时,它会以错误代码 1 退出,根据 ilkkachu 的说法,这是一次成功的零字节系统 read(),因为当没有更多数据可以从文件中读取时就会发生这种情况。

只要文件的读取器仍然是活动进程,系统 read() 调用就可以挂起而不返回。超时可以避免永远挂起。物理驱动器启动和其他连接可能非常慢。假设由于超时而导致 EOF 会很慢并且容易出错。成功的系统 read() 零字节=EOF。

while IFS= read -r -d $'\n' || [[ "$REPLY" ]]; do

|| (逻辑或)测试的存在是为了处理文件不以回车符结尾的情况。根据-d,bash read读取到回车就会成功返回。即使数据已成功读取,Bash 读取也会失败并显示代码 1,因为失败时会以非零代码 1 退出,这是 bash 读取中继 EOF 的方式。

任何将信息从输入中继到输出的程序都可以选择对其在数据流中看到的信息做出反应。

控制台 tty(现在为 pty 或伪 termimal)行读取器/编辑器 (ReadLine) 对从键盘读取的许多字符和转义序列做出反应,这赋予了它们特殊的含义。例如:Control-H 执行退格键,Control-D 发送 EOF 信号(称为 EOT 或传输结束),而 tty 本身保持打开状态,并且可以在另一次读取时发送更多信息。

相关内容