- r - 以节省内存的方式增长 data.frame
- ruby-on-rails - ruby/ruby on rails 内存泄漏检测
- android - 无法解析导入android.support.v7.app
- UNIX 域套接字与共享内存(映射文件)
如果我使用这样的命令:
./program >> a.txt &
,并且该程序是一个长时间运行的程序,那么我只能在程序结束后看到输出。这意味着在它真正停止计算之前,我无法知道计算是否进展顺利。我希望能够在程序运行时读取文件上的重定向输出。
这类似于打开一个文件,向其添加内容,然后在每次写入后将其关闭。如果文件仅在程序结束时关闭,则在程序结束之前无法读取其中的数据。我所知道的唯一重定向类似于在程序结束时关闭文件。
您可以使用这个小的 Python 脚本对其进行测试。语言无所谓。任何写入标准输出的程序都有同样的问题。
l = range(0,100000)
for i in l:
if i%1000==0:
print i
for j in l:
s = i + j
可以通过以下方式运行:
./python 程序.py >> a.txt &
然后 cat a.txt .. 只有在脚本完成计算后您才会得到结果。
最佳答案
来自 stdout
manual page :
The stream stderr is unbuffered. The stream stdout is line-buffered when it points to a terminal. Partial lines will not appear until fflush(3) or exit(3) is called, or a new‐line is printed.
底线:除非输出是一个终端,否则您的程序将在默认情况下以全缓冲模式进行标准输出。这实质上意味着它将以大块的形式输出数据,而不是逐行输出,更不用说逐字符输出了。
解决此问题的方法:
修正你的程序:如果你需要实时输出,你需要修正你的程序。在 C 中你可以使用 fflush(stdout)
在每个输出语句之后,或 setvbuf()
改变标准输出的缓冲模式。对于 Python,有 sys.stdout.flush()
甚至一些建议 here .
使用可以从 PTY 记录的实用程序,而不是直接的标准输出重定向。 GNU Screen可以为您做这件事:
screen -d -m -L python test.py
将是一个开始。这会将程序的输出记录到名为 screenlog.0
的文件中(或类似)在当前目录中,默认延迟 10 秒,您可以使用 screen
连接到运行命令的 session 以提供输入或终止它。延迟和日志文件的名称可以在配置文件中更改,也可以在连接到后台 session 后手动更改。
编辑:
在大多数 Linux 系统上,还有第三种解决方法:您可以使用 LD_PRELOAD
变量和一个预加载的库来覆盖 C 库的选择函数并使用它们来设置 stdout
当您的程序调用这些函数时的缓冲模式。此方法可能有效,但它有许多缺点:
它对静态可执行文件根本不起作用
它很脆弱而且很丑。
它对 SUID 可执行文件根本不起作用 - 动态加载器将拒绝读取 LD_PRELOAD
出于安全原因加载此类可执行文件时的变量。
它很脆弱而且很丑。
它要求您找到并覆盖您的程序在初始设置 stdout
之后 调用的库函数。缓冲模式,最好是 before 任何输出。 getenv()
是许多程序的不错选择,但不是全部。您可能必须重写常见的 I/O 函数,例如 printf()
或 fwrite()
- 如果到了紧要关头,你可能只需要覆盖所有控制缓冲模式的函数,并为 stdout
引入一个特殊条件。 .
它很脆弱而且很丑。
很难确保没有不受欢迎的副作用。要正确执行此操作,您必须确保只有 stdout
受到影响,并且您的覆盖不会使程序的其余部分崩溃,例如stdout
已关闭。
我有没有提到它很脆弱而且很丑陋?
也就是说,这个过程相对简单。你放入一个 C 文件,例如linebufferedstdout.c
替换函数:
#define _GNU_SOURCE
#include <stdlib.h>
#include <stdio.h>
#include <dlfcn.h>
char *getenv(const char *s) {
static char *(*getenv_real)(const char *s) = NULL;
if (getenv_real == NULL) {
getenv_real = dlsym(RTLD_NEXT, "getenv");
setlinebuf(stdout);
}
return getenv_real(s);
}
然后将该文件编译为共享对象:
gcc -O2 -o linebufferedstdout.so -fpic -shared linebufferedstdout.c -ldl -lc
然后你设置LD_PRELOAD
变量以将其与您的程序一起加载:
$ LD_PRELOAD=./linebufferedstdout.so python test.py | tee -a test.out
0
1000
2000
3000
4000
如果你幸运的话,你的问题将得到解决,没有不幸的副作用。
您可以设置 LD_PRELOAD
shell 中的库,如有必要,甚至在 /etc/ld.so.preload
中指定系统范围内的库(绝对不推荐) .
关于linux - 即时输出重定向,在程序仍在运行时查看文件重定向输出,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5500515/
我是一名优秀的程序员,十分优秀!