如何检查stdin是否有数据而不阻塞IO(docker)?

如何检查stdin是否有数据而不阻塞IO(docker)?

如果我执行echo this | docker run -i alpine cat,我就会得到this
如果我执行docker run -i alpine cat,我会被阻止终端,因为cat读取标准输入,但那里什么也没有。

我可以检查打开的文件描述符。如果我运行docker run -i alpine ls -lA /proc/1/fd,我会在标准输出中得到以下内容:

lr-x------    1 root     root            64 Aug  9 13:45 0 -> pipe:[10289389]
l-wx------    1 root     root            64 Aug  9 13:45 1 -> pipe:[10289390]
l-wx------    1 root     root            64 Aug  9 13:45 2 -> pipe:[10289391]
lr-x------    1 root     root            64 Aug  9 13:45 3

这在标准错误中:

ls: /proc/1/fd/3: cannot read link: No such file or directory

一切echo this | docker run -i alpine ls -lA /proc/1/fd都是一样的(除了pipe:[these numbers])。

如果我不-i从 中删除docker run,有什么方法可以检查 stdin 中是否有任何数据而不需要 IO 块?test -t 0根本不起作用,因为 stdin fd 始终打开。


我想创建一个docker run mycommand从 stdin 读取并输出到 stdout 的 CLI 命令(通过 )(stdout 很简单,没有什么有趣的)。所以,我希望echo data | docker run mycommand它能够根据输入数据打印出不同的内容。但如果我要这样做,docker run mycommand应该说我“需要向标准输入提供数据”才能工作。

答案1

是的,您可以在 shell 中确定是否有任何数据要读取。我保存了大量有关 shell 输入读取的信息。

https://antofthy.gitlab.io/info/shell/input_reading.txt

你的问题...“有什么方法可以检查 stdin 中是否有任何数据而不需要 IO 块吗?”

您基本上是在要求“民意调查”(无读)测试......

read -r -t 0 var

这实际上并没有读取任何内容。如果有要读取的内容,则其退出状态为 0(真),否则返回 1;如果没有或为 EOF,则返回假。

另请注意,这仅告诉您是否有数据。在您尝试读取之前,它不会告诉您输入是否位于“文件结尾”(EOF)。它也不会告诉您输入是否是完整的行(带有换行符)。

要在不阻塞的情况下读取可用数据...

  read -r -t 0.00001 line

请记住,大多数内容都会读取整行,并且通常会阻塞输入,直到获得换行符或 EOF。如果没有可用的换行符,上面的代码将返回错误退出 142 和空行,即使对于后面跟有 EOF 的不完整行也是如此。

要读取所有数据,甚至是否可用换行符(将包括任何换行符)...

  while IFS= read -r -s -d '' -t .01 data
  do [ $? -ge 128 ] && break
    printf "$data"
  done

在读取中添加 -n1 将一次读取一个字符!

我建议您仔细阅读上述文档的各个部分,以找出您想要的内容。根据任何其他编程语言的怪癖,所有这些都同样适用于该语言。

额外的

您可能还想查看我编写的名为“shell_select”的 perl 脚本,它允许您检查列出的文件描述符是否已准备好从 shell 读取或写入!

https://antofthy.gitlab.io/software/#shell_select

我用它来处理多个输入流(来自原始“bc”数学计算器的 stdout 和 stderr),而不会挂在(阻塞)一个或另一个文件句柄上,同时仍然保持输入完全独立。

相关内容