我想阅读stdinGo程序的原始内容。例如,如果我这样做了echo test stdin | go run test.go,我希望可以访问“ test stdin”。我尝试从中读取os.Stdin,但是如果其中没有任何内容,则它将等待输入。我也尝试过先检查大小,但是os.Stdin.Stat().Size()即使输入传入也为0。
stdin
echo test stdin | go run test.go
os.Stdin
os.Stdin.Stat().Size()
我能做什么?
我认为您的问题本身没有明智的答案,因为没有“初始标准输入”之类的东西。类似于Unix的操作系统和Windows都实现了“标准流”的概念,它的工作原理如下(简化):创建进程时,它会自动打开三个文件描述符(Windows中的句柄)— stdin,stdout和stderr。毫无疑问,您对这个概念很熟悉,但是我想强调一下“ stream”一词的含义-在您的示例中,当您调用
$ echo 'test stdin' | ./stdin
外壳程序创建一个管道,产生两个进程(一个为echo您的二进制文件,一个为您的二进制文件),并利用它创建的管道:该管道的write FD附加到echo‘stdout,并且该管道的read FD附加到二进制文件的stdin。然后,无论需要将echo哪个过程写入其标准输出,都将通过管道(原文如此!)传递到您的过程的标准输入。(实际上,当今大多数shell echo都是作为内置基元实现的,但这并没有以任何方式改变语义;您也可以尝试/bin/echo使用它,它是一个真实的程序。还要注意,我只是用来./stdin指代您的程序- 最后是为了清楚起见,就像go run stdin.go这样做一样。)
echo
/bin/echo
./stdin
go run stdin.go
请注意以下几个关键事项:
echo -n
read
让我们总结一下:您观察到的行为是正确和正常的。如果希望从stdin获取任何数据,则不要期望它随时可用。如果您也不想在stdin上进行阻止,则创建一个goroutine,它将以无限循环的方式阻止对stdin的读取(但要检查EOF条件),并将收集到的数据通过通道向上传递(可能经过某些处理,如果需要)。
1这就是为什么某些工具在管道中两个管道之间通常会发生,比如grep,可能有特殊的选项,使它们写在每行后刷新它们的标准输出-阅读有关--line- buffered的选项grep手册页的一个例子。那些不了解这种“默认情况下完全缓冲”语义的人会感到困惑,为什么tail -f /path/to/some/file.log | grep whatever | sed ...当监视文件很明显被更新时,它似乎停滞并且什么也不显示。
grep
--line- buffered
tail -f /path/to/some/file.log | grep whatever | sed ...
附带说明:如果您要按原样运行二进制文件,例如
$ ./stdin
这并不意味着产生的进程将没有stdin(或“ initial stdin”或whaveter),相反,它的stdin将连接到您的shell接收键盘输入的同一流(因此您可以直接在进程的stdin中键入内容)。
使进程的stdin无处连接的唯一确定方法是使用
$ ./stdin </dev/null
在类似Unix的操作系统上
C:\> stdin <NUL
在Windows上。此“空设备”使进程read从其标准输入中首先看到EOF 。