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

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

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

问题

package main

import (
	"bufio"
	"os"
)

func main() {
	bw := bufio.NewWriter(os.Stdin)
	bw2 := bufio.NewWriter(os.Stdout)

	bw.WriteString("你好,世界 1\n")
	bw2.WriteString("你好,世界 2\n")

	bw.Flush()
	bw2.Flush()
}

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

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

  • 在我的本地机器上运行:
$ go run myworkspace/main/main.go
你好,世界 1
你好,世界 2
  • 在 playground 上运行:
# 在 'Output' 部分
---
你好,世界 2

程序已退出。
英文:
package main

import (
	"bufio"
	"os"
)

func main() {
	bw := bufio.NewWriter(os.Stdin)
	bw2 := bufio.NewWriter(os.Stdout)

	bw.WriteString("Hello, world 1\n")
	bw2.WriteString("Hello, world 2\n")

	bw.Flush()
	bw2.Flush()
}

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 :
$ go run myworkspace/main/main.go
Hello, world 1
Hello, world 2
  • on the playground :
# in the 'Output' section
---
Hello, world 2

Program exited.

答案1

得分: 2

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

向下滚动到“关于Playground”

关于Playground

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

Playground有一些限制:

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

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


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

var (
    Stdin  = NewFile(uintptr(syscall.Stdin), "/dev/stdin")
    Stdout = NewFile(uintptr(syscall.Stdout), "/dev/stdout")
    Stderr = NewFile(uintptr(syscall.Stderr), "/dev/stderr")
)

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.

var (
	Stdin  = NewFile(uintptr(syscall.Stdin), "/dev/stdin")
	Stdout = NewFile(uintptr(syscall.Stdout), "/dev/stdout")
	Stderr = NewFile(uintptr(syscall.Stderr), "/dev/stderr")
)

> 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不是以这种方式启动它的进程:

package main

import (
	"fmt"
	"os"
)

func main() {
	_, err := os.Stdin.Write([]byte("Hello\n"))
	if err != nil {
		fmt.Fprintln(os.Stderr, "*** error:", err)
	}
}

// 输出:
// *** error: write /dev/stdin: bad file descriptor
//
// 程序已退出。

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 :

package main

import (
	&quot;fmt&quot;
	&quot;os&quot;
)

func main() {
	_, err := os.Stdin.Write([]byte(&quot;Hello\n&quot;))
	if err != nil {
		fmt.Fprintln(os.Stderr, &quot;*** error:&quot;, err)
	}
}

// Output:
// *** error: write /dev/stdin: bad file descriptor
//
// 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:

确定