stdin stdout stderr

Linux 刘宇帅 6年前 阅读量: 2358

首先我们知道什么是流(stream),流物理设备的输入输出、存储设备上的文件的输入输出都映射到逻辑上的数据流,这是用来消除设备直接差异而抽象的一个概念。 通常情况下每个程序在启动的时候都会定义3个流:stderr、stdout、stderr,分别用来输入、输出、诊断和错误信息的输出,通常他们会被连接到用户终端(tty(4)),但是也可以修改到其他的文件和设备(重定向)。这取决于双亲进程的选择和设置。
Linux的本质是一切皆是文件,输入输出设备也是使用文件的形式存在和管理的,内核启动的时候默认会打开三个I/O设备文件:stdin、stdout、stderr,分别得到的描述符是0,1,2,并且他们分别对应的文件就是 /dev/stdin /dev/stdout /dev/stderr。

shell中的输入输出的使用

我们直接输出字符串,字符串在终端直接显示

> $ echo "test"
test

shell中的输出对象就是标准输出上面的命令跟下面是等价的

> $ echo "test" >/dev/stdout
test

在shell 管道命令中,后面命令的输入就是前面命令的标准输出,例如

> $ echo "test" |grep -v test

我们执行上面的命令那么命令行不会有任何输出因为 echo 的输出目的地不再是 stdout 而是 grep 的输入,而 grep 使用 -v 参数忽略到了 test 字符串,所以 grep 就不会忘标准输出写东西,所以上面命令输出为空。 我们再看下面两条命令

> $ (echo "test" >/dev/stdout) |grep  -v test
> $ (echo "test" >/dev/stderr) |grep -v test
test

为什么第二条会有输出呢?因为在 shell 中标准输出和标准错误的目的地都是命令行窗口,而第二行展示的 test 是标准错误的输出结果,最主要的是管道命令会把前一条命令的标准输出作为下一条命令的输入,而标准错误输出还是作为错误输出到目的地。
我们这里再说下文件重定向。

> $ echo "test"> /tmp/stdout.log
> $ cat /tmp/stdout.log
test

我们把 echo 输出重定向到 /tmp/stdout.log,可以看到终端中没有任何输出,而 /tmp/stdout.log 中可以看到相关内容。
文件重定向同样可以修改标准错误输出目的地

> $ (echo "test" >/dev/stderr) 2> /tmp/stderr.log
> $ cat /tmp/stderr.log
test

我们可以看到终端中没有任何输出,而/tmp/stderr.log 中可以看到相关输出。 输入重定向

> $ cat < /tmp/stdout.log
test

我们知道 cat 的使用方法是 cat filepath,而上面我们使用输入从定向,把/tmpstdout.log作为输入。

Go语言

在 Go 语言中我们在包 os.file 中看到标准输入输出和错误的相关的定义:

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

Go 中3个流对应的文件和系统对应的文件是一致的。
Go 语言中基本使用:

package main

import "fmt"

func main() {
    fmt.Print("stdout")
    println("stderr")
}

stdout 是行缓冲的

有很多地方说 stdout 是行缓冲的,stderr 是不缓冲的。根据上面的说明我们可以知道他们两个都是文件描述符是没有差别的,所以不存在操作系统层面不存在缓冲的问题。上面说的 stdout 缓冲的问题应该是c/c++语言中对两种输出实现做的优化处理。另外在 Go 代码中没有相关逻辑。

提示

功能待开通!


暂无评论~