Skip to main content

Linux 重定向与管道

Linux 数据流 stdin stdout stderr

在 Linux 中,输入输出流是程序和系统交互的核心机制。每个运行的程序都会使用三个标准流:stdin(标准输入)、stdout(标准输出)和 stderr(标准错误)。

1. 什么是标准输入(stdin)?

stdin,全称是标准输入(standard input),是程序接收数据的默认通道。通常情况下,stdin 对应你的键盘输入。程序会从 stdin 读取你敲入的字符、数字或命令。

比如,你运行一个命令行程序,它可能会等着你输入点啥。比如 cat 命令,如果不指定文件,它会从 stdin 读取数据:

cat

运行上面这行代码后,终端会等着你输入。你可以敲几行文字,然后按 Ctrl+D(表示输入结束),cat 会把你输入的内容原样吐到终端上。

  • stdin 的文件描述符:在 Linux 中,stdin 对应的文件描述符是 0。文件描述符是个数字,系统用它来追踪打开的文件或流。
  • 常见场景:像 grepsed 这样的工具,如果没指定输入文件,就会从 stdin 读取数据。

试试这个例子:

echo "hello world" | cat

这里,echo 的输出通过管道(后面会讲)被送到了 cat 的 stdin,cat 再把内容显示出来。

2. 什么是标准输出(stdout)?

stdout,全称标准输出(standard output),是程序输出结果的默认通道。默认情况下,stdout 的内容会显示在你的终端屏幕上。

比如,运行 ls 命令:

ls

它会列出当前目录的文件名,这些输出就是送到 stdout 的。如果你啥也没干,这些内容就会直接出现在终端上。

  • stdout 的文件描述符:stdout 对应文件描述符 1
  • 特点:stdout 通常是程序的“正常”输出,比如命令的执行结果、打印的信息等。

再看个例子:

echo "Hello, Linux!"

echo 命令会把 "Hello, Linux!" 送到 stdout,终端会显示出来。

3. 什么是标准错误(stderr)?

stderr,全称标准错误(standard error),是程序用来输出错误信息的通道。跟 stdout 一样,stderr 的内容默认也会显示在终端上,但它是专门为错误信息准备的。

为啥要分开 stdout 和 stderr?因为这样你可以分别处理正常输出和错误信息。比如,你可能只想看错误信息,或者把错误信息存到文件里,而不混淆正常输出。

试试这个:

ls /notexist

你会看到类似这样的错误:

ls: cannot access '/notexist': No such file or directory

这个错误信息就是送到 stderr 的,而不是 stdout。

  • stderr 的文件描述符:stderr 对应文件描述符 2
  • 特点:stderr 专门处理错误或警告信息,比如文件不存在、权限不足等。

4. stdin、stdout、stderr 的关系

这三个流是每个 Linux 进程默认打开的通道,各自有明确分工:

  • stdin (0):程序从这里读取输入(默认是键盘)。
  • stdout (1):程序的正常输出送到这里(默认是终端)。
  • stderr (2):程序的错误信息送到这里(默认也是终端)。

它们的关系可以用下面这个例子感受一下:

cat nosuchfile.txt

运行这行代码,cat 会尝试读取 nosuchfile.txt,但因为文件不存在,它会通过 stderr 输出错误信息:

cat: nosuchfile.txt: No such file or directory

如果文件存在,cat 会把文件内容送到 stdout 显示出来。

5. 怎么区分 stdout 和 stderr?

在终端上,stdout 和 stderr 的输出看起来都在屏幕上,咋区分呢?其实它们在底层是分开的,后面讲重定向时你会看到,可以把 stdout 和 stderr 分别送到不同地方。

试试这个命令:

ls /etc /nosuchdir

输出可能像这样:

ls: cannot access '/nosuchdir': No such file or directory
/etc:
[一大堆文件名]

这里,/nosuchdir 的错误信息是 stderr,/etc 的目录内容是 stdout。虽然它们都显示在终端,但它们走的是不同的通道。

6. 为什么理解这些流很重要?

stdin、stdout、stderr 是 Linux 命令行操作的基石。后面你会学到:

  • 重定向:把 stdout 或 stderr 保存到文件,或者把文件内容送给 stdin。
  • 管道:把一个命令的 stdout 直接送给另一个命令的 stdin。

这些操作都依赖于你理解这三个流。比如,管道(|)本质上是把前一个命令的 stdout 连接到后一个命令的 stdin。

7. 简单操作 stdin、stdout、stderr

我们可以用文件描述符(0、1、2)来操作这些流。以下是一些基础用法(后面重定向和管道会细讲):

  • 显示 stderr
ls /notexist 2>&1

这里 2>&1 是把 stderr(2)合并到 stdout(1),所以错误信息还是会显示在终端。

  • 读取 stdin
read input
echo "You typed: $input"

运行后,输入一行文字(通过 stdin),read 会把输入存到变量 input,然后 echo 输出到 stdout。

  • 分开 stdout 和 stderr
ls /etc /notexist > output.txt 2> error.txt

这会把 stdout(/etc 的内容)存到 output.txt,把 stderr(错误信息)存到 error.txt