困惑关于stdin,stdout和stderr?
我很困惑这三个文件的目的。 如果我的理解是正确的, stdin
是程序写入其请求中运行进程中的任务的文件。 stdout
是内核写入其输出的文件,并且请求它访问来自stderr
的信息, stderr
是input所有exception的文件。 在打开这些文件来检查这些文件是否真的发生了,我发现似乎没有任何提示!
我想知道的是这些文件的目的究竟是什么,绝对愚蠢的回答用很less的科技术语!
标准input – 这是您的进程读取从您获取信息的文件句柄 。
标准输出 – 您的进程将正常信息写入此文件句柄。
标准错误 – 您的过程在此处写入错误信息。
这就像我可以做到的一样愚蠢:-)
当然,那大多是按照惯例。 如果你愿意的话,没有什么能够阻止你将你的错误信息写入标准输出。 您甚至可以完全closures这三个文件句柄,并打开自己的I / O文件。
当你的进程启动时,它应该已经打开这些句柄,它可以读取和/或写入它们。
默认情况下,它们可能连接到你的terminal设备(例如/dev/tty
),但是在你的进程之前,shell将允许你在这些句柄和特定的文件和/或设备之间build立连接(甚至是连接到其他进程的pipe道)开始(一些操作可能是相当聪明的)。
一个例子是:
my_prog <inputfile 2>errorfile | grep XYZ
这将:
- 为
my_prog
创build一个进程。 - 打开input文件作为标准input(文件句柄0)。
- 打开错误文件作为您的标准错误(文件句柄2)。
- 为
grep
创build另一个进程。 - 将
my_prog
的标准输出my_prog
到grep
的标准input。
重新评论:
当我在/ dev文件夹中打开这些文件时,我怎么从来没有看到正在运行的进程的输出?
这是因为他们不是正常的文件。 尽pipeUNIX将所有内容都呈现为某个文件系统中的某个文件,但这并不是最低级别的文件系统。 /dev
层次结构中的大多数文件都是字符或块设备,实际上是设备驱动程序。 他们没有大小,但他们有一个主要和次要的设备号码。
当你打开它们时,你连接到设备驱动程序而不是物理文件,设备驱动程序足够聪明,知道应该单独处理单独的进程。
Linux /proc
文件系统也是如此。 这些不是真正的文件,只是严格控制内核信息的网关。
说stdin
, stdout
和stderr
是“I / Ostream”而不是文件是更正确的。 正如你所注意到的,这些实体不在文件系统中。 但就I / O而言,Unix哲学就是“一切都是文件”。 实际上,这实际上意味着您可以使用相同的库函数和接口( printf
, scanf
, read
, write
, select
等),而不用担心I / Ostream是否连接到键盘,磁盘文件,套接字,pipe道或其他I / O抽象。
大多数程序需要读取input,写入输出和日志错误,因此为了方便编程, stdin
, stdout
和stderr
是为您预定义的。 这只是一个惯例,并不是由操作系统强制执行的。
恐怕你的理解完全倒退了。 🙂
从程序的angular度来考虑“标准入门”,“标准出局”和“标准错误”,而不是从内核的angular度来看。
当一个程序需要打印输出时,通常打印到“标准输出”。 一个程序通常使用printf
打印输出到标准输出,只打印到标准输出。
当一个程序需要打印错误信息(不一定是例外,这些是一个编程语言结构,强加在更高的层面上),通常打印到“标准错误”。 它通常使用fprintf
,它接受打印时使用的文件stream。 文件stream可以是任何打开的文件:标准输出,标准错误或用fopen
或fdopen
打开的任何其他文件。
当文件需要读取input时,使用“standard in”,使用fread
或fgets
或getchar
。
这些文件中的任何一个都可以轻松地从shell中redirect ,如下所示:
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
grep echo /etc/services | awk '{print $2;}' | sort
将每个程序的标准输出挂钩到stream水线中下一个程序的标准input中。
其次,我已经提供了用于处理文件stream( FILE *
对象)的标准ISO C函数 – 在内核级别,它是所有文件描述符(对文件表的int
引用)和更低级的操作,比如read
和write
,这不会做ISO C函数的快乐缓冲。 我想保持简单,并使用更简单的function,但我认为,你应该知道的替代品。 🙂
标准input
通过控制台读取input(例如键盘input)在C中使用scanf
scanf(<formatstring>,<pointer to storage> ...);
标准输出
产生输出到控制台在C中使用printf
printf(<string>, <values to print> ...);
标准错误
生成“错误”输出到控制台在C中使用fprintf
fprintf(stderr, <string>, <values to print> ...);
redirect
stdin的源可以被redirect。 例如,不是来自键盘input,而是来自文件( echo < file.txt
)或其他程序( ps | grep <userid>
)。
标准输出stderr的目标也可以redirect。 例如stdout可以被redirect到一个文件: ls . > ls-output.txt
ls . > ls-output.txt
,在这种情况下,输出写入文件ls-output.txt
。 Stderr可以redirect到2>
。
使用ps -aux通过调用cat / proc /(pid)/ fd / 0显示当前进程,所有这些进程都列在/ proc / as / proc /(pid)/中,它打印任何在标准输出我认为这个过程。 或许,
/ proc /(pid)/ fd / 0 – 标准输出文件
/ proc /(pid)/ fd / 1 – 标准input文件
/ proc /(pid)/ fd / 2 – 标准错误文件
例如
但是只对/ bin / bash工作起来很好,其他进程通常在0中什么都没有,但是很多有错误写在2中
我认为人们说stderr应该只用于错误信息是有误导性的。 它也应该用于为用户运行命令的信息消息,而不是为数据的任何潜在的下游消费者(即,如果你运行一个shellpipe道链接几个命令,你不需要像“获取项目30” 42424“出现在标准输出上,因为它们会混淆消费者,但是您可能仍然希望用户看到它们。
历史原理见http://www.jstorimer.com/blogs/workingwithcode/7766119-when-to-use-stderr-instead-of-stdout :
“所有的程序都把诊断放在标准输出上,当输出被redirect到一个文件时,总是会引起麻烦,但是当输出发送到一个不知情的进程时,却变得不能容忍,但是不愿意违背标准input – 标准输出模型,人们可以通过v6来容忍这种状态,此后不久,Dennis Ritchie通过引入标准错误文件来削减Gordian结,这还不够,pipe道诊断可能来自同时运行的多个程序中的任何一个。自我认同“。
具有关联缓冲的文件被称为stream,并被声明为指向定义typesFILE的指针。 fopen()函数为stream创build特定的描述性数据,并返回一个指针指向所有后续事务中的stream。 通常有三个打开的stream,在头文件中声明常量指针并与标准的打开文件关联。 在程序启动时,预定义了三个stream,不需要明确打开:标准input(用于读取常规input),标准输出(用于写入常规输出)和标准错误(用于写入诊断输出)。 标准错误stream打开时没有完全缓冲; 标准input和标准输出stream是完全缓冲的,当且仅当stream可以被确定为不涉及交互设备时