我想从围棋程序的原版stdin读一读.例如,如果我使用echo test stdin | go run test.go,我会希望能够访问"test stdin".我试着从os.Stdin开始读取,但是如果里面什么都没有,那么它将等待输入.我也try 先判断大小,但即使传入输入,os.Stdin.Stat().Size()也是0.

我能做什么?

推荐答案

I think your question per se has no sensible answer because there's just no such thing as "initial stdin". Unix-like OSs, and Windows implement the concept of "standard streams", which works like this (simplified): when a process is created, it automagically has three file descriptors (handles in Windows) open — stdin, stdout and stderr. No doubts, you're familiar with this concept, but I'd like to stress the meaning of the word "stream" there — in your example, when you call

$ echo 'test stdin' | ./stdin

the shell creates a pipe, spawns two processes (one for echo and one for your binary) and makes use of the pipe it created: the pipe's write FD is attached to the echo's stdout and the pipe's read FD is attached to your binary's stdin. Then whatever the echo process pleases to write to its stdout is piped (sic!) to the stdin of your process. (In reality most today's shells implement echo as a built-in primitive but this does not in any way change the semantics; your could as well have tried /bin/echo instead, which is a real program. Also note that I just used ./stdin to refer to your program — this is for clarity, as go run stdin.go would do exactly this, in the end.)

请注意以下几点:

  • 写入过程(在您的示例中为echo)不会被忽略以向其标准输出写入任何内容(例如,echo -n不会向其标准输出写入任何内容并成功退出).
  • 它还可以任意延迟写入数据(要么是因为它想要这样的延迟,要么是因为它已经被操作系统抢占,或者在某个系统调用中Hibernate ,等待某个繁忙的系统资源,等等).
  • 操作系统缓冲区通过管道传输.这意味着书写过程发送到管道的内容可能会在阅读端以任意块的形式出现1
  • 只有两种方法可以知道写入端没有更多的数据要通过管道发送:
    • 以某种方式将其编码在数据本身中(这意味着在写入器和读取器之间使用商定的数据传输协议).
    • 写入器可能会关闭其管道一侧,这将导致读取器端出现"文件结束"情况(但仅在缓冲区耗尽并try 另一个调用read,但调用失败)之后.

让我们来总结一下:你观察到的行为是正确和正常的.如果您希望从stdin获得任何数据,则不能期望这些数据随时可用.如果您也不想在标准输入上使用挡路,那么创建一个goroutine,它将在一个无限循环中对标准输入执行阻塞读取(但判断EOF条件),并通过通道向上传递收集到的数据(如果需要,可能在进行了某些处理之后).

1 This is why certain tools which usually occur between two pipes in a pipeline, such as grep, might have special options to make them flush their stdout after writing each line — read about the --line-buffered option in the grep manual page for one example. People who are not aware of this "full buffering by default" semantics are puzzled why tail -f /path/to/some/file.log | grep whatever | sed ... seems to stall and not display anything when it's obvious the monitored file gets updated.


附注:如果您要"按原样"运行您的二进制文件,如下面的

$ ./stdin

这并不意味着生成的进程将没有stdin(或"initial stdin"或whavier),相反,它的stdin将连接到shell从中接收键盘导入的同一个流(因此可以直接在进程的stdin中键入内容).

将进程的标准输入连接到任何地方的唯一可靠方法是使用

$ ./stdin </dev/null

在类Unix操作系统和

C:\> stdin <NUL

在windows 上.这"null device"使过程在其标准输入的第一个read上看到EOF.

Go相关问答推荐

在字符串与字符串子切片上使用len进行位转移产生意外输出

如何修复在Go API中使用Gin Framework的请求资源上没有使用Gin Framework的请求源的消息?''

golang 的条件储存库

Go在使用HTTP代理时如何处理DNS请求?

golang.org/x/oauth2 oauth2.Config.Endpoint.TokenURL mock:缺少access_token

可以';t从主机连接到ScyllaDB容器

如何修复 Go 中协议缓冲区定义中重新定义的字段?

Go 1.20 中如何计算连接错误?

Prometheus 摘要分位数错误

Golang Docker Selenium Chrome

将 firestoreinteger_value转换为整数

如何使用 go-git 将特定分支推送到远程

有没有办法计算枚举中定义的项目总数?

读取非UTF8编码的文件内容并正确打印出来

无法使用 Golang 扫描文件路径

Golang Gin 绑定请求正文 XML 到 Slice

Go 泛型:自引用接口约束

切片到数组指针的转换

递归数据 struct 解组在 Go Lang Protobuf 中给出错误无法解析无效的线格式数据

使用 LoadLibraryA(path_to_dll) 加载 DLL 会将文件描述符 0、1 和 2 的继承句柄标志 (HANDLE_FLAG_INHERIT) 从 1 更改为 0