为什么在本地使用bufio.NewWriter获取os.Stdin时要正常运行?

huangapple go评论125阅读模式
英文:

Why operate normally when bufio.NewWriter get os.Stdin in local

问题

  1. package main
  2. import (
  3. "bufio"
  4. "os"
  5. )
  6. func main() {
  7. bw := bufio.NewWriter(os.Stdin)
  8. bw2 := bufio.NewWriter(os.Stdout)
  9. bw.WriteString("你好,世界 1\n")
  10. bw2.WriteString("你好,世界 2\n")
  11. bw.Flush()
  12. bw2.Flush()
  13. }

这段代码在本地环境中显示了两个字符串。但为什么在不同的环境中表现不同呢?

我的本地环境:
操作系统:macOS 12.6
Go 版本:go1.19.2 darwin/amd64
IDE:vscode

  • 在我的本地机器上运行:
  1. $ go run myworkspace/main/main.go
  2. 你好,世界 1
  3. 你好,世界 2
  • 在 playground 上运行:
  1. # 在 'Output' 部分
  2. ---
  3. 你好,世界 2
  4. 程序已退出。
英文:
  1. package main
  2. import (
  3. "bufio"
  4. "os"
  5. )
  6. func main() {
  7. bw := bufio.NewWriter(os.Stdin)
  8. bw2 := bufio.NewWriter(os.Stdout)
  9. bw.WriteString("Hello, world 1\n")
  10. bw2.WriteString("Hello, world 2\n")
  11. bw.Flush()
  12. bw2.Flush()
  13. }

This code show both string in a local environment.
But why does it work differently in different environments?

My local environment
OS : macOS 12.6
go : go1.19.2 darwin/amd64
ide : vscode

  • on my local machine :
  1. $ go run myworkspace/main/main.go
  2. Hello, world 1
  3. Hello, world 2
  • on the playground :
  1. # in the 'Output' section
  2. ---
  3. Hello, world 2
  4. Program exited.

答案1

得分: 2

Go Playground
https://go.dev/play/p/PtoDwCZGggd

向下滚动到“关于Playground”

关于Playground

Go Playground在一个沙盒中运行程序。

Playground有一些限制:

Playground程序与外界的唯一通信方式是通过标准输出和标准错误输出。

Go Playground会忽略对标准输入的写入。


在本地,os.Stdin是一个文件。

  1. var (
  2. Stdin = NewFile(uintptr(syscall.Stdin), "/dev/stdin")
  3. Stdout = NewFile(uintptr(syscall.Stdout), "/dev/stdout")
  4. Stderr = NewFile(uintptr(syscall.Stderr), "/dev/stderr")
  5. )

Stdin、Stdout和Stderr是打开的文件,指向标准输入、标准输出和标准错误的文件描述符。

英文:

The Go Playground
https://go.dev/play/p/PtoDwCZGggd

Scroll all the way down to "About the Playground"

> About the Playground
>
> The Go Playground runs the program inside a sandbox.
>
> There are limitations to the programs that can be run in the playground:
>
> The only communication a playground program has to the outside world is by writing to standard output and standard error.

The Go Playground discards writes to standard input.


Locally, os.Stdin is a file.

  1. var (
  2. Stdin = NewFile(uintptr(syscall.Stdin), "/dev/stdin")
  3. Stdout = NewFile(uintptr(syscall.Stdout), "/dev/stdout")
  4. Stderr = NewFile(uintptr(syscall.Stderr), "/dev/stderr")
  5. )

> Stdin, Stdout, and Stderr are open Files pointing to the standard input, standard output, and standard error file descriptors.

答案2

得分: 2

底线是:当程序启动时,你的程序无法控制将使用什么作为标准输入和标准输出。

在你的本地机器上尝试运行:echo "" | go run main.gogo run main.go < anyfile

(另外:你应该在你的Go代码中检查错误)


在从终端运行命令时,标准设置是,shell使用相同的文件描述符,该文件描述符指向一个读/写终端,用于标准输入和标准输出/标准错误。在这种设置下,写入标准输入是“可行的”。

但是你不能依赖它(实际上你不应该这样做),事实证明playground不是以这种方式启动它的进程:

  1. package main
  2. import (
  3. "fmt"
  4. "os"
  5. )
  6. func main() {
  7. _, err := os.Stdin.Write([]byte("Hello\n"))
  8. if err != nil {
  9. fmt.Fprintln(os.Stderr, "*** error:", err)
  10. }
  11. }
  12. // 输出:
  13. // *** error: write /dev/stdin: bad file descriptor
  14. //
  15. // 程序已退出。

https://go.dev/play/p/NmxgOsK2ovp


另请参阅:

https://stackoverflow.com/questions/37822580/why-is-it-possible-to-write-to-stdin

https://stackoverflow.com/questions/7383803/writing-to-stdin-and-reading-from-stdout-unix-linux-c-programming

(通过搜索“writing to stdin”找到的)

英文:

The bottom line is : your program does not control what thingy will be used as Stdin and Stdout when it is started.

On your local machine, try running : echo &quot;&quot; | go run main.go or go run main.go &lt; anyfile.

(also : you should check for errors in your go code)


It is a standard setup, when running a command from a terminal, that the shell uses the same file descriptor, which points to a read/write terminal, for stdin and stdout/stderr. With that setup, writing to stdin "works".

But you can't rely on it (you shouldn't, actually), and it turns out that the playground doesn't start its processes that way :

  1. package main
  2. import (
  3. &quot;fmt&quot;
  4. &quot;os&quot;
  5. )
  6. func main() {
  7. _, err := os.Stdin.Write([]byte(&quot;Hello\n&quot;))
  8. if err != nil {
  9. fmt.Fprintln(os.Stderr, &quot;*** error:&quot;, err)
  10. }
  11. }
  12. // Output:
  13. // *** error: write /dev/stdin: bad file descriptor
  14. //
  15. // Program exited.

https://go.dev/play/p/NmxgOsK2ovp


see also :

https://stackoverflow.com/questions/37822580/why-is-it-possible-to-write-to-stdin

https://stackoverflow.com/questions/7383803/writing-to-stdin-and-reading-from-stdout-unix-linux-c-programming

(found by googling "writing to stdin")

huangapple
  • 本文由 发表于 2022年10月21日 14:00:15
  • 转载请务必保留本文链接:https://go.coder-hub.com/74149330.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定