【发布时间】:2011-03-24 01:08:53
【问题描述】:
我对这三个文件的用途感到很困惑。如果我的理解是正确的,stdin 是程序写入其请求以在进程中运行任务的文件,stdout 是内核写入其输出的文件,请求它的进程从, stderr 是输入所有异常的文件。在打开这些文件以检查这些文件是否确实发生时,我发现似乎没有任何建议!
我想知道这些文件的确切用途是什么,用很少的技术术语绝对愚蠢的回答!
【问题讨论】:
我对这三个文件的用途感到很困惑。如果我的理解是正确的,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 将 everything 呈现为文件系统中某处的文件,但在最低级别并没有做到这一点。 /dev 层次结构中的大多数文件是字符设备或块设备,实际上是设备驱动程序。它们没有大小,但有主要和次要设备号。
当您打开它们时,您将连接到设备驱动程序而不是物理文件,并且设备驱动程序足够智能,知道应该单独处理单独的进程。
Linux /proc 文件系统也是如此。这些不是真正的文件,只是内核信息受到严格控制的网关。
【讨论】:
xyz >xyz.out 会将您的标准输出写入一个物理文件,其他进程可以读取该文件。 xyz | grep something 将更直接地将xyz 标准输出连接到grep 标准输入。如果您希望不受限制地访问您无法以这种方式控制的进程,则需要查看/proc 之类的内容,或者编写代码以通过某种方式连接到内核来过滤输出。可能还有其他解决方案,但它们都可能彼此一样危险:-)
/dev/stdin 是指向/proc/self/fd/0 的符号链接——当前正在运行的程序打开的第一个文件描述符。因此,/dev/stdin 所指向的内容会因程序而异,因为/proc/self/ 始终指向“当前正在运行的程序”。 (无论哪个程序都在执行open 调用。)/dev/stdin 和朋友们被放在那里以使 setuid shell 脚本更安全,并让您将文件名 /dev/stdin 传递给仅处理文件的程序,但您想控制更多交互式地。 (总有一天这会成为你知道的一个有用的技巧。:)
更正确的说法是 stdin、stdout 和 stderr 是“I/O 流”而不是
比文件。正如您所注意到的,这些实体并不存在于文件系统中。但是
就 I/O 而言,Unix 哲学是“一切都是文件”。在实践中,
这实际上意味着您可以使用相同的库函数和接口 (printf,
scanf、read、write、select等)无需担心I/O流是否
连接到键盘、磁盘文件、套接字、管道或其他一些 I/O 抽象。
大多数程序需要读取输入、写入输出和记录错误,所以stdin、stdout、
和stderr 是为您预定义的,以方便编程。这只是
一种约定,操作系统不强制执行。
【讨论】:
【讨论】:
echo 的标准输入交互。事实上,如果您将echo 替换为读取 标准输入的程序,它就会坐在那里等待您的终端输入。在这种情况下,hello 作为参数提供(通过argc/argv)。如果您看到如下所述的效果,那么关于 2>&1 和 &> 具有相同效果的评论是准确的:“将标准错误与标准输出合并”。他们都这样做,但方式略有不同。等价的将是> somefile 2>&1 和&> somefile。
恐怕你的理解完全倒退了。 :)
从程序的角度考虑“标准输入”、“标准输出”和“标准错误”,而不是从内核的角度。
当程序需要打印输出时,它通常会打印到“标准输出”。程序通常使用printf 将输出打印到标准输出,而printf 只会打印到标准输出。
当程序需要打印错误信息(不一定是异常,那些是编程语言结构,强加于更高级别)时,它通常会打印到“标准错误”。它通常使用fprintf 执行此操作,它接受打印时使用的文件流。文件流可以是任何为写入而打开的文件:标准输出、标准错误或任何其他使用fopen 或fdopen 打开的文件。
当文件需要读取输入时使用“标准输入”,使用fread或fgets或getchar。
这些文件中的任何一个都可以从 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
或者,整个墨西哥卷饼:
cat < /etc/passwd > /tmp/out 2> /tmp/err
有两个重要的警告:首先,“标准输入”、“标准输出”和“标准错误”只是一个约定。它们是一个非常强大的约定,但这只是一个协议,能够运行这样的程序非常好:grep echo /etc/services | awk '{print $2;}' | sort 并将每个程序的标准输出连接到标准输入流水线中的下一个程序。
其次,我给出了用于处理文件流(FILE * 对象)的标准 ISO C 函数——在内核级别,它是所有文件描述符(int 对文件表的引用),而且要低得多像read 和write 这样的级别操作,它们不能很好地缓冲ISO C 函数。我想保持简单并使用更简单的功能,但我认为你应该知道替代方案。 :)
【讨论】:
我认为人们说 stderr 应该只用于错误消息是误导性的。
它也应该用于为运行命令的用户而不是任何潜在的数据下游消费者提供的信息性消息(即,如果您运行一个链接多个命令的 shell 管道,您不想要信息性消息,例如“getting 42424 中的第 30 项”出现在 stdout 上,因为它们会使消费者感到困惑,但您可能仍希望用户看到它们。
请参阅 this 了解历史原因:
“所有程序都在标准输出上放置了诊断信息。这有 当输出被重定向到一个文件时总是会引起麻烦,但是 当输出被发送到一个毫无戒心的人时变得无法容忍 过程。然而,不愿意违反简单的 标准输入标准输出模型,人们可以容忍这种状态 事务通过 v6。此后不久,丹尼斯·里奇砍下了戈迪安 通过引入标准误差文件来打结。这还不够。 使用管道诊断可以来自多个程序中的任何一个 同时运行。需要通过诊断来识别自己。”
【讨论】:
通过控制台读取输入(例如键盘输入)。 在 C 中与 scanf 一起使用
scanf(<formatstring>,<pointer to storage> ...);
产生到控制台的输出。 在 C 中与 printf 一起使用
printf(<string>, <values to print> ...);
向控制台生成“错误”输出。 在 C 中与 fprintf 一起使用
fprintf(stderr, <string>, <values to print> ...);
标准输入源可以重定向。例如,它可以来自文件(echo < file.txt)或另一个程序(ps | grep <userid>),而不是来自键盘输入。
stdout、stderr 的目的地也可以被重定向。例如,stdout 可以重定向到一个文件:ls . > ls-output.txt,在这种情况下,输出被写入文件ls-output.txt。 Stderr can be redirected 和 2>。
【讨论】:
使用 ps -aux 显示当前进程,所有这些都列在 /proc/ 作为 /proc/(pid)/,通过调用 cat /proc/(pid)/fd/0 它打印在我认为该过程的标准输出。所以也许,
/proc/(pid)/fd/0 - 标准输出文件
/proc/(pid)/fd/1 - 标准输入文件
/proc/(pid)/fd/2 - 标准错误文件
例如
但只对 /bin/bash 有效,其他进程通常在 0 中没有任何内容,但许多在 2 中写入错误
【讨论】:
有关这些文件的权威信息,请查看手册页,在终端上运行命令。
$ man stdout
但对于一个简单的答案,每个文件都是为了:
stdout 用于流输出
stdin 用于流输入
stderr 用于打印错误或日志消息。
每个 unix 程序都有这些流中的每一个。
【讨论】:
stderr 不会进行 IO 缓存缓冲,因此如果我们的应用程序需要打印关键消息信息(一些错误、异常)到控制台或文件,请使用它,因为使用 stdout 打印一般日志信息,因为它使用 IO 缓存缓冲有在将我们的消息写入文件应用程序之前可能会关闭,从而使调试变得复杂
【讨论】:
具有关联缓冲的文件称为流,并被声明为指向已定义类型 FILE 的指针。 fopen() 函数为流创建某些描述性数据,并返回一个指针以指定所有后续事务中的流。通常有三个打开的流,它们在标头中声明并与标准打开文件相关联的常量指针。 在程序启动时,三个流是预定义的,不需要显式打开:标准输入(用于读取常规输入)、标准输出(用于写入常规输出)和标准错误(用于写入诊断输出)。打开时,标准错误流没有完全缓冲;当且仅当可以确定流不引用交互式设备时,标准输入和标准输出流才会被完全缓冲
【讨论】:
这是一篇关于stdin、stdout 和stderr 的长文:
总结一下:
像文件一样处理流
Linux 中的流(几乎与其他所有内容一样)被视为 它们是文件。您可以从文件中读取文本,也可以编写文本 成一个文件。这两个动作都涉及数据流。所以 将数据流作为文件处理的概念并没有那么复杂 拉伸。
与进程关联的每个文件都分配有一个唯一编号 识别它。这称为文件描述符。每当一个动作 需要对文件执行,文件描述符用于 识别文件。
这些值始终用于标准输入、标准输出和标准错误:
0: stdin 1: stdout 2: stderr
具有讽刺意味的是,我在堆栈溢出和上面的文章中发现了这个问题,因为我正在搜索有关异常/非标准流的信息。所以我的搜索还在继续。
【讨论】: