对stdin,stdout和stderr感到困惑?

Sho*_*vik 199 linux stdin stdout stderr

我对这三个文件的目的感到困惑.如果我的理解是正确的,stdin程序写入其在进程中运行任务的请求stdout的文件是内核写入其输出stderr的文件,并且请求它的进程从中访问信息,并且是文件到输入所有例外情况.在打开这些文件以检查这些文件是否确实发生时,我发现似乎没有任何建议!

我想知道的是这些文件的目的究竟是什么,用非常少的技术术语绝对愚蠢地回答!

pax*_*blo 221

标准输入 - 这是您的进程读取的文件句柄,以从您那里获取信息.

标准输出 - 您的进程将正常信息写入此文件句柄.

标准错误 - 您的进程将错误信息写入此文件句柄.

这就像我能做到的那样愚蠢:-)

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

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

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

一个例子是:

my_prog <inputfile 2>errorfile | grep XYZ
Run Code Online (Sandbox Code Playgroud)

这将:

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

你的评论:

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

这是因为它们不是普通文件.虽然UNIX 在某个地方将文件系统中的所有文件都显示为文件,但这并不是最低级别的文件系统./dev层次结构中的大多数文件都是字符或块设备,实际上是设备驱动程序.它们没有大小,但它们有一个主设备号和次设备号.

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

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

  • @Shouvik,请注意`/ dev/stdin`是`/ proc/self/fd/0`的符号链接 - 当前正在运行的程序已打开的第一个文件描述符.因此,`/ dev/stdin`指向的内容将在程序之间发生变化,因为`/ proc/self /`总是指向'当前正在运行的程序'.(无论哪个程序正在执行`open`调用.)`/ dev/stdin`和朋友被放在那里使setuid shell脚本更安全,并让你将文件名`/ dev/stdin`传递给只能处理文件的程序,但是你想要更加互动地控制.(总有一天,这将是一个有用的技巧,让你知道.:) (19认同)
  • 因为那些不是技术上的文件.它们是设备节点,表示要写入的特定设备.UNIX可能会将所有内容_present_作为文件抽象,但这并不是最深层次的. (7认同)
  • 那是你的回应。虽然我可以从你的描述中理解文件的目的,但我想再移动一个级别。当我在 /dev 文件夹中打开这些文件时,为什么我永远看不到正在运行的进程的输出。假设我在终端上执行 top ,它不应该定期将其结果输出到 stdout 文件中,因此当它被更新时,我应该能够看到输出的实例被打印到这个文件上。但事实并非如此......所以这些文件不一样(/dev 目录中的文件)。 (2认同)
  • @CarlosW.Mercado,*文件*是数据的物理表现形式。例如,存储在硬盘上的位。文件*句柄*(通常)是一个小标记,用于在打开该文件后引用该文件。 (2认同)
  • 请注意,“stderr”通常用于诊断消息。实际上,只有*正常输出*应该写入“stdout”。我有时看到人们将日志分成“stdout”和“stderr”。这不是预期的使用方式。整个日志应该完全进入“stderr”。 (2认同)
  • @Oswin,已将其更改为使用 ISO 标准中的术语(常规和诊断),因为这是最终来源。 (2认同)

Jim*_*wis 54

这将是更正确的说stdin,stdoutstderr有"I/O流",而不是文件.正如您所注意到的,这些实体并不存在于文件系统中.但就I/O而言,Unix哲学是"一切都是文件".在实践中,真正意味着你可以使用相同的库功能和接口(printf, scanf,read,write,select,等),而不必担心I/O流是否连接到键盘,磁盘文件,插座,管道,或其他一些I/O抽象.

大多数程序需要读取输入,输出写入,并记录错误,所以stdin,stdoutstderr预定义的你,作为一个编程方便.这只是一种约定,并不是由操作系统强制执行的.


Leo*_*ult 40

作为上述答案的补充,这里是关于重定向的总结: 重定向备忘单

  • 您的评论与已接受的答案相结合是很有意义的,并且可以清楚地说明问题!谢谢! (4认同)
  • 一张图片胜过千言万语 ! (2认同)
  • 事实上,第一个是完全错误的。“hello”绝不与“echo”的标准输入交互。事实上,如果您用一个“读取”标准输入的程序替换“echo”,它就会坐在那里等待您的终端输入。在本例中,“hello”作为参数提供(通过“argc/argv”)。如果您看到如下所述的效果,则关于“2&gt;&amp;1”和“&amp;&gt;”具有相同效果的注释是准确的:“将 stderr 与 stdout 合并”。他们都这样做,但方式略有不同。等价的是 `&gt; somefile 2&gt;&amp;1` 和 `&amp;&gt; somefile`。 (2认同)

sar*_*old 22

我担心你的理解是完全倒退的.:)

程序的角度考虑"标准输入","标准输出"和"标准错误" ,而不是从内核的角度来看.

当程序需要打印输出时,它通常打印到"标准输出".程序通常将输出打印到标准输出printf,仅打印到标准输出.

当程序需要打印错误信息时(不一定是异常,那些是编程语言结构,强加到更高的级别),它通常会打印到"标准错误".它通常使用fprintf,它接受打印时使用的文件流.文件流可以是为写入而打开的任何文件:标准输出,标准错误或使用fopen或打开的任何其他文件fdopen.

当文件需要读取输入时,使用"标准输入",使用freadfgets,或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
Run Code Online (Sandbox Code Playgroud)

或者,整个辣酱玉米饼馅:

cat < /etc/passwd > /tmp/out 2> /tmp/err
Run Code Online (Sandbox Code Playgroud)

有两个重要的警告:第一,"标准输入","标准输出"和"标准错误"只是一种惯例.它们是一个非常强大的约定,但它只是一个协议,能够运行这样的程序是非常好的:grep echo /etc/services | awk '{print $2;}' | sort并且将每个程序的标准输出挂钩到管道中下一个程序的标准输入.

其次,我已经给出了用于处理文件流(FILE *对象)的标准ISO C函数- 在内核级别,它是所有文件描述符(int对文件表的引用)和更低级别的操作,如readwrite,它们不快乐缓冲ISO C功能.我想保持简单并使用更简单的功能,但我认为你应该知道其他选择.:)


mik*_*002 8

标准输入

通过控制台读取输入(例如键盘输入).在C中使用scanf

scanf(<formatstring>,<pointer to storage> ...);
Run Code Online (Sandbox Code Playgroud)

标准输出

生成输出到控制台.在C中使用printf

printf(<string>, <values to print> ...);
Run Code Online (Sandbox Code Playgroud)

标准错误

产生"错误"输出到控制台.在C中使用fprintf

fprintf(stderr, <string>, <values to print> ...);
Run Code Online (Sandbox Code Playgroud)

重定向

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

stdout,stderr的目标也可以重定向.例如,stdout可以重定向到文件:ls . > ls-output.txt在这种情况下,输出将写入文件ls-output.txt. 标准错误可以重定向2>.


dee*_*dee 7

我认为有人说stderr只应将错误消息用于误导。

它也应该用于提供给运行该命令的用户的信息性消息,而不是给数据的任何潜在下游使用者(例如,如果您运行将多个命令链接在一起的Shell管道,则您不希望获得诸如“获取第30条信息”之类的信息性消息)。 42424“出现在屏幕上,stdout因为它们会使消费者感到困惑,但是您可能仍希望用户看到它们。

这个历史的理由:

“所有程序都会对标准输出进行诊断。这总是在将输出重定向到文件时引起麻烦,但是在将输出发送到毫无疑问的过程时变得无法忍受。尽管如此,不愿意违反标准输入的简单性在标准输出模型中,人们通过v6容忍了这种情况,此后不久,丹尼斯·里奇(Dennis Ritchie)通过引入标准错误文件削减了戈尔迪诺结,这还远远不够,利用管道诊断可以来自多个同时运行的程序。诊断程序需要识别自己。”


小智 5

使用 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 中写入了错误