在Linux(以及所有类似Unix的系统)中,shell总是为每个进程提供三个打开的文件描述符。文件描述符编号为0、1和2,通常标记为“标准输入”(通常简称为“stdin”,尽管它最初是一个C库符号,用于标识通常连接到标准输入的缓冲I/O结构)、“标准输出”(stdout)和“标准错误”(stderr)。(为了简洁起见,我将使用下面的简短版本。)
默认情况下,这些文件描述符都是用来引用终端输入和输出的。使用竖线(|)语法时,shell会创建一个称为管道的单向进程间通信机制,并将第一个命令的stdout“连接”到管道的写入端,将第二个命令的stdin“连接”到管道的读端。未提及的文件描述符将保留其默认值(即第一个命令的stdin、第二个命令的stdout和这两个命令的stderr仍然连接到终端)。在
通常,Linux/Unix程序将错误消息和其他诊断信息写入stderr描述符。当没有进行stdout重定向时,这似乎与stdout无法区分(因为两者都连接到终端)。但是当stdout被重定向到管道时,stderr不受影响;它仍然连接到终端。在
在您的例子中,您将管道的读取端连接到tee,后者将其stdin(这里接收python脚本的stdout)复制到一个文件,并连接到其自己的stdout(在本例中仍然是终端)。当python脚本抛出异常时,python解释器将异常信息和堆栈跟踪输出到它的stderr。既然你还没有重定向stderr,它就要去终端了。但是,由于您还将脚本的stdout的副本发送到终端(通过tee),所以不明显一组输出通过tee发送到终端,而另一组直接发送到终端。当然,tee从来没有看到异常信息。在
所以有两个简单的方法可以保存异常信息。首先,可以将异常信息保存到单独的文件中:python optimisation.py 2>error.txt | tee output.txt & disown
语法“2>;错误表“告诉shell将文件描述符2(stderr)重定向到名为”错误表". 在
其次,如果希望异常信息与脚本的stdout一起保存,请使用以下语法:
^{pr2}$
语法指定stdout和stderr都应指向管道。(实际上有许多不同的语法可以实现这一点。这个最简短。)