什么是 Linux 上的标准输入、标准输出和标准错误?

stdin
、stdout
和 stderr
是启动 Linux 命令时创建的三个数据流。您可以使用它们来判断您的脚本是通过管道传输还是重定向。我们告诉你如何。
流连接两点
一旦开始学习 Linux 和类 Unix 操作系统,您就会遇到术语 stdin
、stdout
和 stederr
.这是执行 Linux 命令时建立的三个标准流。在计算中,流是可以传输数据的东西。在这些流的情况下,该数据是文本。
数据流,就像水流一样,有两端。它们有来源和流出。无论您使用哪个 Linux 命令,都会提供每个流的一端。另一端由启动命令的 shell 确定。根据启动命令的命令行,该端将连接到终端窗口、连接到管道或重定向到文件或其他命令。
Linux 标准流
在 Linux 中,stdin
是标准输入流。这接受文本作为输入。从命令到 shell 的文本输出通过 stdout
(标准输出)流传送。命令的错误消息通过 stderr
(标准错误)流发送。
所以你可以看到有两种输出流,stdout
和stderr
,以及一种输入流,stdin
。因为错误消息和正常输出都有自己的管道将它们传送到终端窗口,所以它们可以相互独立处理。
流像文件一样处理
Linux 中的流——就像几乎所有其他东西一样——被视为文件。您可以从文件中读取文本,也可以将文本写入文件。这两个操作都涉及数据流。因此,将数据流作为文件处理的概念并没有那么牵强。
与进程关联的每个文件都分配了一个唯一的编号来标识它。这称为文件描述符。每当需要对文件执行操作时,文件描述符用于标识该文件。
这些值始终用于 stdin
、stdout、
和 stderr
:
- 0:标准输入
- 1:标准输出
- 2:标准错误
对管道和重定向做出反应
为了简化某人对某个主题的介绍,一种常用的技术是教授该主题的简化版本。例如,对于语法,我们被告知规则是“I 在 E 之前,除了在 C 之后”。但实际上,这条规则的例外情况要多于遵守它的情况。
同样,在谈论 stdin
、stdout
和 stderr
时,可以很方便地抛出进程既不知道也不知道的公认公理关心它的三个标准流在哪里终止。一个进程应该关心它的输出是去终端还是被重定向到一个文件中?它甚至可以判断它的输入是来自键盘还是从另一个进程通过管道传输到它?
实际上,一个进程确实知道——或者至少它可以发现,如果它选择检查——并且如果软件作者决定添加该功能,它可以相应地改变它的行为。
我们可以很容易地看到这种行为变化。试试这两个命令:
ls

ls | cat

如果 ls
命令的输出 (stdout
) 被传送到另一个命令,则它的行为会有所不同。切换到单列输出的是 ls
,它不是 cat
执行的转换。如果输出被重定向,ls
做同样的事情:
ls > capture.txt

cat capture.txt

重定向标准输出和标准错误
通过专用流传递错误消息有一个优势。这意味着我们可以将命令的输出 (stdout
) 重定向到一个文件,并且仍然可以在终端窗口中看到任何错误消息 (stderr
)。如果需要,您可以在错误发生时对错误做出反应。它还会阻止错误消息污染 stdout
已重定向到的文件。
在编辑器中输入以下文本并将其保存到名为 error.sh 的文件中。
#!/bin/bash
echo "About to try to access a file that doesn't exist"
cat bad-filename.txt
使用此命令使脚本可执行:
chmod +x error.sh
脚本的第一行通过 stdout
流将文本回显到终端窗口。第二行试图访问一个不存在的文件。这将生成通过 stderr
传递的错误消息。
使用此命令运行脚本:
./error.sh

我们可以看到,stdout
和 stderr
这两个输出流都已显示在终端窗口中。

让我们尝试将输出重定向到一个文件:
./error.sh > capture.txt

通过 stderr
传递的错误消息仍会发送到终端窗口。我们可以检查文件的内容以查看 stdout
输出是否进入了文件。
cat capture.txt

stdin
的输出已按预期重定向到文件。

>
重定向符号默认与 stdout
配合使用。您可以使用其中一个数字文件描述符来指示您希望重定向哪个标准输出流。
要显式重定向 stdout
,请使用此重定向指令:
1>
要显式重定向 stderr
,请使用此重定向指令:
2>
让我们再次尝试我们的测试,这次我们将使用 2>
:
./error.sh 2> capture.txt

错误消息被重定向,stdout
echo
消息被发送到终端窗口:

让我们看看 capture.txt 文件中有什么。
cat capture.txt

stderr
消息按预期位于 capture.txt 中。

重定向 stdout 和 stderr
当然,如果我们可以将 stdout
或 stderr
重定向到一个彼此独立的文件,我们应该能够同时将它们重定向到两个不同的文件?
我们可以。此命令会将 stdout
定向到名为 capture.txt 的文件,并将 stderr
定向到名为 error.txt 的文件。
./error.sh 1> capture.txt 2> error.txt

因为输出流——标准输出和标准错误——都被重定向到文件,所以在终端窗口中没有可见的输出。我们返回到命令行提示符,就好像什么都没发生一样。

让我们检查每个文件的内容:
cat capture.txt
cat error.txt

将 stdout 和 stderr 重定向到同一个文件
很好,我们让每个标准输出流都进入了它自己的专用文件。我们唯一可以做的其他组合是将 stdout
和 stderr
发送到同一个文件。
我们可以使用以下命令来实现:
./error.sh > capture.txt 2>&1
让我们分解一下。
- ./error.sh:启动 error.sh 脚本文件。
- > capture.txt:将
stdout
流重定向到 capture.txt 文件。>
是1>
的简写。 - 2>&1:这使用 &> 重定向指令。该指令允许您告诉 shell 使一个流到达与另一个流相同的目的地。在这种情况下,我们说的是“将流 2,
stderr
重定向到流 1,stdout
,被重定向到的相同目的地。”

没有可见的输出。这是令人鼓舞的。

让我们检查一下 capture.txt 文件,看看里面有什么。
cat capture.txt

stdout
和 stderr
流都已重定向到单个目标文件。
要将流的输出重定向并悄悄丢弃,请将输出定向到 /dev/null
。
检测脚本中的重定向
我们讨论了命令如何检测是否有任何流被重定向,并可以选择相应地改变其行为。我们可以在自己的脚本中完成这个吗?我们可以。这是一种非常容易理解和使用的技术。
在编辑器中输入以下文本并将其保存为 input.sh。
#!/bin/bash
if [ -t 0 ]; then
echo stdin coming from keyboard
else
echo stdin coming from a pipe or a file
fi
使用以下命令使其可执行:
chmod +x input.sh
聪明的部分是方括号内的测试。如果与文件描述符关联的文件在终端窗口中终止,则 -t
(终端)选项返回真 (0)。我们使用文件描述符 0 作为测试的参数,它代表 stdin
。
如果 stdin
连接到终端窗口,测试将证明是正确的。如果 stdin
连接到文件或管道,测试将失败。
我们可以使用任何方便的文本文件来生成脚本的输入。这里我们使用一个名为 dummy.txt 的文件。
./input.sh < dummy.txt

输出显示脚本识别出输入不是来自键盘,而是来自文件。如果您愿意,您可以相应地改变脚本的行为。

那是文件重定向,让我们用管道试试。
cat dummy.txt | ./input.sh

该脚本识别出它的输入正在通过管道传输到它。或者更准确地说,它再次识别出 stdin
流没有连接到终端窗口。

让我们在既不使用管道也不使用重定向的情况下运行脚本。
./input.sh

stdin
流连接到终端窗口,脚本会相应地报告这一点。
要用输出流检查同样的事情,我们需要一个新的脚本。在编辑器中输入以下内容并将其保存为 output.sh。
#!/bin/bash
if [ -t 1 ]; then
echo stdout is going to the terminal window
else
echo stdout is being redirected or piped
fi
使用以下命令使其可执行:
chmod +x input.sh
此脚本的唯一重大变化是方括号中的测试。我们使用数字 1 表示 stdout
的文件描述符。
让我们试试看。我们将通过 cat
管道输出。
./output | cat

该脚本识别出它的输出不会直接进入终端窗口。

我们还可以通过将输出重定向到文件来测试脚本。
./output.sh > capture.txt

终端窗口没有输出,我们静静地返回到命令提示符。正如我们所料。

我们可以查看 capture.txt 文件以查看捕获的内容。使用以下命令来执行此操作。
cat capture.sh

同样,我们脚本中的简单测试检测到 stdout
流没有直接发送到终端窗口。
如果我们在没有任何管道或重定向的情况下运行脚本,它应该检测到 stdout
被直接传送到终端窗口。
./output.sh

这正是我们所看到的。

意识流
知道如何判断您的脚本是否连接到终端窗口或管道,或者是否正在被重定向,可以让您相应地调整它们的行为。
日志记录和诊断输出可以或多或少详细,这取决于它是进入屏幕还是文件。错误消息可以记录到与正常程序输出不同的文件中。
通常情况下,更多的知识会带来更多的选择。
Linux Commands | ||
Files | tar · pv · cat · tac · chmod · grep · diff · sed · ar · man · pushd · popd · fsck · testdisk · seq · fd · pandoc · cd · $PATH · awk · join · jq · fold · uniq · journalctl · tail · stat · ls · fstab · echo · less · chgrp · chown · rev · look · strings · type · rename · zip · unzip · mount · umount · install · fdisk · mkfs · rm · rmdir · rsync · df · gpg · vi · nano · mkdir · du · ln · patch · convert · rclone · shred · srm · scp · gzip · chattr · cut · find · umask · wc | |
Processes | alias · screen · top · nice · renice · progress · strace · systemd · tmux · chsh · history · at · batch · free · which · dmesg · chfn · usermod · ps · chroot · xargs · tty · pinky · lsof · vmstat · timeout · wall · yes · kill · sleep · sudo · su · time · groupadd · usermod · groups · lshw · shutdown · reboot · halt · poweroff · passwd · lscpu · crontab · date · bg · fg · pidof · nohup · pmap | |
Networking | netstat · ping · traceroute · ip · ss · whois · fail2ban · bmon · dig · finger · nmap · ftp · curl · wget · who · whoami · w · iptables · ssh-keygen · ufw · arping · firewalld |
RELATED: Best Linux Laptops for Developers and Enthusiasts