对 stdin、stdout 和 stderr 感到困惑吗?

发布于 2024-09-12 13:48:19 字数 222 浏览 10 评论 0 原文

我对这三个文件的用途感到相当困惑。如果我的理解是正确的,stdin 是程序写入其在进程中运行任务的请求的文件,stdout 是内核写入其任务的文件。输出和请求它的进程从中访问信息,stderr 是输入所有异常的文件。在打开这些文件以检查这些是否确实发生时,我发现似乎没有任何迹象表明如此!

我想知道的是这些文件的确切用途是什么,完全用很少的技术术语来简单地回答!

I am rather confused with the purpose of these three files. If my understanding is correct, stdin is the file in which a program writes into its requests to run a task in the process, stdout is the file into which the kernel writes its output and the process requesting it accesses the information from, and stderr is the file into which all the exceptions are entered. On opening these files to check whether these actually do occur, I found nothing seem to suggest so!

What I would want to know is what exactly is the purpose of these files, absolutely dumbed down answer with very little tech jargon!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(11

も让我眼熟你 2024-09-19 13:48:19

标准输入|STDIN - 这是您的进程读取以获取信息的文件句柄

标准输出|STDOUT - 您的进程将常规输出写入此文件句柄。

标准错误|STDERR - 您的进程将诊断输出写入此文件句柄。

这已经是我所能做到的最简单的了:-)

当然,这主要是按照惯例。如果您愿意,没有什么可以阻止您将诊断信息写入标准输出。您甚至可以完全关闭三个文件句柄并打开您自己的 I/O 文件。

当您的进程启动时,它应该已经打开了这些句柄,并且只能读取和/或写入它们。

默认情况下,它们可能连接到您的终端设备(例如,/dev/tty),但 shell 将允许您在这些句柄与特定文件和/或设备(甚至管道)之间建立连接在进程启动之前(某些可能的操作相当聪明)。

一个例子是:

my_prog <inputfile 2>errorfile | grep XYZ

它将:

  • my_prog 创建一个进程。
  • 打开 inputfile 作为标准输入(文件句柄 0)。
  • 打开 errorfile 作为标准错误(文件句柄 2)。
  • grep 创建另一个进程。
  • my_prog 的标准输出附加到 grep 的标准输入。

回复您的评论:

当我在 /dev 文件夹中打开这些文件时,为什么我永远看不到正在运行的进程的输出?

这是因为它们不是普通文件。虽然 UNIX 将一切都呈现为文件系统中某处的文件,但这并不意味着在最低级别上也是如此。 /dev 层次结构中的大多数文件都是字符设备或块设备,实际上是设备驱动程序。它们没有尺寸,但有主设备号和次设备号。

当您打开它们时,您将连接到设备驱动程序而不是物理文件,并且设备驱动程序足够聪明,知道应该单独处理单独的进程。

Linux /proc 文件系统也是如此。这些不是真正的文件,只是严格控制的内核信息网关。

Standard input|STDIN - this is the file handle that your process reads to get information from you.

Standard output|STDOUT - your process writes conventional output to this file handle.

Standard error|STDERR - your process writes diagnostic output to this file handle.

That's about as dumbed-down as I can make it :-)

Of course, that's mostly by convention. There's nothing stopping you from writing your diagnostic information to standard output if you wish. You can even close the three file handles totally and open your own files for I/O.

When your process starts, it should already have these handles open and it can just read from and/or write to them.

By default, they're probably connected to your terminal device (e.g., /dev/tty) but shells will allow you to set up connections between these handles and specific files and/or devices (or even pipelines to other processes) before your process starts (some of the manipulations possible are rather clever).

An example being:

my_prog <inputfile 2>errorfile | grep XYZ

which will:

  • create a process for my_prog.
  • open inputfile as your standard input (file handle 0).
  • open errorfile as your standard error (file handle 2).
  • create another process for grep.
  • attach the standard output of my_prog to the standard input of grep.

Re your comment:

When I open these files in /dev folder, how come I never get to see the output of a process running?

It's because they're not normal files. While UNIX presents everything as a file in a file system somewhere, that doesn't make it so at the lowest levels. Most files in the /dev hierarchy are either character or block devices, effectively a device driver. They don't have a size but they do have a major and minor device number.

When you open them, you're connected to the device driver rather than a physical file, and the device driver is smart enough to know that separate processes should be handled separately.

The same is true for the Linux /proc filesystem. Those aren't real files, just tightly controlled gateways to kernel information.

凡尘雨 2024-09-19 13:48:19

更正确的说法是,stdinstdoutstderr 是“I/O 流”,而不是
比文件。正如您所注意到的,这些实体并不存在于文件系统中。但是
就 I/O 而言,Unix 哲学是“一切皆文件”。在实践中,
这实际上意味着您可以使用相同的库函数和接口(printf
scanfreadwriteselect等)而不用担心I/O流是否存在
连接到键盘、磁盘文件、套接字、管道或其他一些 I/O 抽象。

大多数程序需要读取输入、写入输出和记录错误,因此 stdinstdout
stderr 是为您预定义的,以方便编程。这只是
一种约定,并且不是由操作系统强制执行的。

It would be more correct to say that stdin, stdout, and stderr are "I/O streams" rather
than files. As you've noticed, these entities do not live in the filesystem. But the
Unix philosophy, as far as I/O is concerned, is "everything is a file". In practice,
that really means that you can use the same library functions and interfaces (printf,
scanf, read, write, select, etc.) without worrying about whether the I/O stream
is connected to a keyboard, a disk file, a socket, a pipe, or some other I/O abstraction.

Most programs need to read input, write output, and log errors, so stdin, stdout,
and stderr are predefined for you, as a programming convenience. This is only
a convention, and is not enforced by the operating system.

昵称有卵用 2024-09-19 13:48:19

作为上述答案的补充,以下是有关重定向的总结:
重定向备忘单

编辑:该图形并不完全正确。

第一个示例根本不使用 stdin,它将“hello”作为参数传递给 echo 命令。

该图还表明 2>&1 与 &> 具有相同的效果。然而

ls Documents ABC > dirlist 2>&1
#does not give the same output as 
ls Documents ABC > dirlist &>

这是因为&>需要重定向到一个文件,2>&1 只是将 stderr 发送到 stdout

As a complement of the answers above, here is a sum up about Redirections:
Redirections cheatsheet

EDIT: This graphic is not entirely correct.

The first example does not use stdin at all, it's passing "hello" as an argument to the echo command.

The graphic also says 2>&1 has the same effect as &> however

ls Documents ABC > dirlist 2>&1
#does not give the same output as 
ls Documents ABC > dirlist &>

This is because &> requires a file to redirect to, and 2>&1 is simply sending stderr into stdout

a√萤火虫的光℡ 2024-09-19 13:48:19

恐怕你的理解完全倒退了。 :)

程序的角度思考“标准输入”、“标准输出”和“标准错误”,而不是从内核的角度。

当程序需要打印输出时,它通常打印到“标准输出”。程序通常使用 printf 将输出打印到标准输出,它仅打印到标准输出。

当程序需要打印错误信息(不一定是例外,这些是编程语言构造,在更高级别上强加)时,它通常打印为“标准错误”。它通常使用 fprintf 来实现,它接受打印时使用的文件流。文件流可以是为写入而打开的任何文件:标准输出、标准错误或使用 fopenfdopen 打开的任何其他文件。

当文件需要使用 freadfgetsgetchar 读取输入时,使用“standard in”。

这些文件中的任何一个都可以轻松地从 shell 重定向,如下所示:

cat /etc/passwd > /tmp/out     # redirect cat's standard out to /tmp/foo
cat /nonexistant 2> /tmp/err   # redirect cat's standard error to /tmp/error
cat < /etc/passwd              # redirect cat's standard input to /etc/passwd

或者,整个 enchilada:

cat < /etc/passwd > /tmp/out 2> /tmp/err

有两个重要的警告:首先,“标准输入”、“标准输出”和“标准错误” “只是一个约定。它们是一个非常强的约定,但这只是一个协议,即能够运行这样的程序是非常好的:grep echo /etc/services | awk '{print $2;}' | sort 并将每个程序的标准输出连接到管道中下一个程序的标准输入。

其次,我给出了用于处理文件流(FILE * 对象)的标准 ISO C 函数——在内核级别,它是所有文件描述符(int 引用)到文件表)以及低级操作(例如读取和写入),这些操作无法实现 ISO C 函数的良好缓冲。我想保持简单并使用更简单的功能,但我认为您仍然应该知道替代方案。 :)

I'm afraid your understanding is completely backwards. :)

Think of "standard in", "standard out", and "standard error" from the program's perspective, not from the kernel's perspective.

When a program needs to print output, it normally prints to "standard out". A program typically prints output to standard out with printf, which prints ONLY to standard out.

When a program needs to print error information (not necessarily exceptions, those are a programming-language construct, imposed at a much higher level), it normally prints to "standard error". It normally does so with fprintf, which accepts a file stream to use when printing. The file stream could be any file opened for writing: standard out, standard error, or any other file that has been opened with fopen or fdopen.

"standard in" is used when the file needs to read input, using fread or fgets, or getchar.

Any of these files can be easily redirected from the shell, like this:

cat /etc/passwd > /tmp/out     # redirect cat's standard out to /tmp/foo
cat /nonexistant 2> /tmp/err   # redirect cat's standard error to /tmp/error
cat < /etc/passwd              # redirect cat's standard input to /etc/passwd

Or, the whole enchilada:

cat < /etc/passwd > /tmp/out 2> /tmp/err

There are two important caveats: First, "standard in", "standard out", and "standard error" are just a convention. They are a very strong convention, but it's all just an agreement that it is very nice to be able to run programs like this: grep echo /etc/services | awk '{print $2;}' | sort and have the standard outputs of each program hooked into the standard input of the next program in the pipeline.

Second, I've given the standard ISO C functions for working with file streams (FILE * objects) -- at the kernel level, it is all file descriptors (int references to the file table) and much lower-level operations like read and write, which do not do the happy buffering of the ISO C functions. I figured to keep it simple and use the easier functions, but I thought all the same you should know the alternatives. :)

凡间太子 2024-09-19 13:48:19

我认为人们说 stderr 应该仅用于错误消息是误导性的。

它还应该用于为运行命令的用户提供信息性消息,而不是为数据的任何潜在下游消费者提供信息(即,如果您运行链接多个命令的 shell 管道,则您不需要诸如“获取第 30 项”之类的信息性消息。 42424”出现在 stdout 上,因为它们会让消费者感到困惑,但您可能仍然希望用户看到它们。

请参阅 了解历史原理:

“所有程序都将诊断放在标准输出上。这有
当输出重定向到文件时总是会引起麻烦,但是
当输出被发送到毫无戒心的人时变得无法忍受
过程。尽管如此,还是不​​愿意违背简单性
标准输入标准输出模型,人们容忍这种状态
通过 v6 处理事务。此后不久,丹尼斯·里奇(Dennis Ritchie)剪掉了戈尔迪安(Gordian)
通过引入标准误差文件来解决这个问题。这还不够。
通过管道,诊断可以来自多个程序中的任何一个
同时运行。需要进行诊断来识别自己的身份。”

I think people saying stderr should be used only for error messages is misleading.

It should also be used for informative messages that are meant for the user running the command and not for any potential downstream consumers of the data (i.e. if you run a shell pipe chaining several commands you do not want informative messages like "getting item 30 of 42424" to appear on stdout as they will confuse the consumer, but you might still want the user to see them.

See this for historical rationale:

"All programs placed diagnostics on the standard output. This had
always caused trouble when the output was redirected into a file, but
became intolerable when the output was sent to an unsuspecting
process. Nevertheless, unwilling to violate the simplicity of the
standard-input-standard-output model, people tolerated this state of
affairs through v6. Shortly thereafter Dennis Ritchie cut the Gordian
knot by introducing the standard error file. That was not quite enough.
With pipelines diagnostics could come from any of several programs
running simultaneously. Diagnostics needed to identify themselves."

童话里做英雄 2024-09-19 13:48:19

stdin

通过控制台读取输入(例如键盘输入)。
在 C 中与 scanf

scanf(<formatstring>,<pointer to storage> ...);

stdout

一起使用生成到控制台的输出。
在 C 中与 printf

printf(<string>, <values to print> ...);

stderr

一起使用生成“错误”输出到控制台。
在 C 中与 fprintf 一起使用

fprintf(stderr, <string>, <values to print> ...);

重定向

stdin 的源可以被重定向。例如,它可以来自文件 (echo < file.txt) 或另一个程序 (ps | grep ),而不是来自键盘输入)。

stdout、stderr 的目的地也可以重定向。例如,stdout 可以重定向到文件: ls 。 > ls-output.txt,在本例中,输出将写入文件 ls-output.txtStderr 可以使用 >2>

stdin

Reads input through the console (e.g. Keyboard input).
Used in C with scanf

scanf(<formatstring>,<pointer to storage> ...);

stdout

Produces output to the console.
Used in C with printf

printf(<string>, <values to print> ...);

stderr

Produces 'error' output to the console.
Used in C with fprintf

fprintf(stderr, <string>, <values to print> ...);

Redirection

The source for stdin can be redirected. For example, instead of coming from keyboard input, it can come from a file (echo < file.txt ), or another program ( ps | grep <userid>).

The destinations for stdout, stderr can also be redirected. For example stdout can be redirected to a file: ls . > ls-output.txt, in this case the output is written to the file ls-output.txt. Stderr can be redirected with 2>.

万劫不复 2024-09-19 13:48:19

使用 ps -aux 显示当前进程,所有进程都在 /proc/ 中列为 /proc/(pid)/,通过调用 cat /proc/(pid)/fd/0 它会打印在标准输出中找到的任何内容我认为这个过程。所以也许

/proc/(pid)/fd/0 - 标准输出文件
/proc/(pid)/fd/1 - 标准输入文件
/proc/(pid)/fd/2 - 标准错误文件

例如 my Terminal window

但只能这样工作对于 /bin/bash 来说,其他进程通常在 0 中没有任何内容,但许多进程在 2 中写入了错误

Using ps -aux reveals current processes, all of which are listed in /proc/ as /proc/(pid)/, by calling cat /proc/(pid)/fd/0 it prints anything that is found in the standard output of that process I think. So perhaps,

/proc/(pid)/fd/0 - Standard Output File
/proc/(pid)/fd/1 - Standard Input File
/proc/(pid)/fd/2 - Standard Error File

for examplemy terminal window

But only worked this well for /bin/bash other processes generally had nothing in 0 but many had errors written in 2

枕梦 2024-09-19 13:48:19

有关这些文件的权威信息,请查看手册页,并在终端上运行命令。

$ man stdout 

但对于一个简单的答案,每个文件都用于:

stdout 用于流输出

stdin 用于流输入

stderr 用于打印错误或日志消息。

每个 UNIX 程序都有这些流中的每一个。

For authoritative information about these files, check out the man pages, run the command on your terminal.

$ man stdout 

But for a simple answer, each file is for:

stdout for a stream out

stdin for a stream input

stderr for printing errors or log messages.

Each unix program has each one of those streams.

云巢 2024-09-19 13:48:19

stderr 不会进行 IO 缓存缓冲,因此如果我们的应用程序需要将关键消息信息(一些错误、异常)打印到控制台或文件,请使用它,就像使用 stdout 打印一般日志信息一样,因为它使用 IO 缓存缓冲,有可能在将消息写入文件之前,应用程序可能会关闭,从而使调试变得复杂

stderr will not do IO Cache buffering so if our application need to print critical message info (some errors ,exceptions) to console or to file use it where as use stdout to print general log info as it use IO Cache buffering there is a chance that before writing our messages to file application may close ,leaving debugging complex

青朷 2024-09-19 13:48:19

这是一篇关于 stdin 、 stdout 和 stderr 的长文:

总结一下:

流像文件一样处理

Linux 中的流——就像几乎所有其他东西一样——被视为
它们是文件。您可以从文件中读取文本,也可以写入文本
到一个文件中。这两个操作都涉及数据流。所以
将数据流作为文件处理的概念并不是那么简单
拉伸。

与进程关联的每个文件都分配有一个唯一的编号
识别它。这称为文件描述符。每当一个动作
需要对文件执行,文件描述符用于
识别文件。

这些值始终用于 stdin、stdout 和 stderr:

<前><代码>0:标准输入
1:标准输出
2:标准错误

具有讽刺意味的是,我在堆栈溢出和上面的文章中发现了这个问题,因为我正在搜索有关异常/非标准流的信息。所以我的搜索仍在继续。

Here is a lengthy article on stdin, stdout and stderr:

To summarize:

Streams Are Handled Like Files

Streams in Linux—like almost everything else—are treated as though
they were files. You can read text from a file, and you can write text
into a file. Both of these actions involve a stream of data. So the
concept of handling a stream of data as a file isn’t that much of a
stretch.

Each file associated with a process is allocated a unique number to
identify it. This is known as the file descriptor. Whenever an action
is required to be performed on a file, the file descriptor is used to
identify the file.

These values are always used for stdin, stdout, and stderr:

0: stdin
1: stdout
2: stderr

Ironically I found this question on stack overflow and the article above because I was searching for information on abnormal / non-standard streams. So my search continues.

萌逼全场 2024-09-19 13:48:19

具有关联缓冲的文件称为流,并被声明为指向已定义类型 FILE 的指针。 fopen() 函数为流创建某些描述性数据,并返回一个指针以在所有后续事务中指定该流。通常,存在三个打开的​​流,其常量指针在标头中声明并与标准打开文件关联。
在程序启动时,预定义了三个流,无需显式打开:标准输入(用于读取常规输入)、标准输出(用于写入常规输出)和标准错误(用于写入诊断输出)。打开时,标准错误流未完全缓冲;当且仅当可以确定流不引用交互式设备时,标准输入和标准输出流才被完全缓冲

https://www.mkssoftware.com/docs/man5/stdio.5.asp

A file with associated buffering is called a stream and is declared to be a pointer to a defined type FILE. The fopen() function creates certain descriptive data for a stream and returns a pointer to designate the stream in all further transactions. Normally there are three open streams with constant pointers declared in the header and associated with the standard open files.
At program startup three streams are predefined and need not be opened explicitly: standard input (for reading conventional input), standard output (for writing conventional output), and standard error (for writing diagnostic output). When opened the standard error stream is not fully buffered; the standard input and standard output streams are fully buffered if and only if the stream can be determined not to refer to an interactive device

https://www.mkssoftware.com/docs/man5/stdio.5.asp

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文