我有一个长期运行的 python 脚本,它定期将数据输出到我用以下内容调用的标准输出:
python script.py > output.txt
Run Code Online (Sandbox Code Playgroud)
这个脚本已经运行了一段时间,我想用Ctrl+停止它,C但不要丢失任何输出。不幸的是,当我实现该脚本时,我忘记在每行输出之后使用类似sys.stdout.flush()(之前建议的强制输出刷新的解决方案)来刷新缓冲区,因此现在调用Ctrl+C将导致我丢失所有输出。
如果想知道是否有任何方法可以与正在运行的 python 脚本(或更一般地说,正在运行的进程)交互以强制它刷新其输出缓冲区。我不是在问如何编辑和重新运行脚本以使其正确刷新 - 这个问题特别是关于与正在运行的进程进行交互(并且,在我的情况下,不会丢失当前代码执行的输出)。
lor*_*nix 19
如果真的想要这些数据,我建议将gdb调试器附加到 python 解释器,暂时停止任务,调用fsync(1)(stdout),从中分离(恢复进程)并仔细阅读输出文件。
查看/proc/$(pidof python)/fd以查看有效的文件描述符。$(pidof x)返回名为“ x”的进程的 PID 。
# your python script is running merrily over there.... with some PID you've determined.
#
# load gdb
gdb
#
# attach to python interpreter (use the number returned by $(pidof python))
attach 1234
#
# force a sync within the program's world (1 = stdout, which is redirected in your example)
call fsync(1)
#
# the call SHOULD have returned 0x0, sync successful. If you get 0xffffffff (-1), perhaps that wasn't stdout. 0=stdin, 1=stdout, 2=stderr
#
# remove our claws from poor python
detach
#
# we're done!
quit
Run Code Online (Sandbox Code Playgroud)
我已经使用这种方法来更改工作目录,即时调整设置......很多事情。唉,你只能调用在运行程序中定义的函数,fsync不过效果很好。
(gdb 命令 ' info functions' 将列出所有可用的函数。但要小心。您正在对进程进行实时操作。)
还有一个命令peekfd(可以在psmiscDebian Jessie 和其他人的软件包中找到),它可以让您查看隐藏在进程缓冲区中的内容。同样,/proc/$(pidof python)/fd将向您显示有效的文件描述符作为 peekfd 的参数。
如果你不记得-upython,你总是可以在命令前加上stdbuf(in coreutils,已经安装) 来根据需要将 stdin/stdout/stderr 设置为 unbuffered、line buffered 或 block buffered:
stdbuf -i 0 -o 0 -e 0 python myscript.py > unbuffered.output
Run Code Online (Sandbox Code Playgroud)
当然man pages是你的朋友,嘿嘿!也许别名在这里也很有用。
alias python='python -u'
Run Code Online (Sandbox Code Playgroud)
现在你的 python 总是-u用于你所有的命令行工作!
首先确保你有 Python(或至少是 glibc)的调试符号。在Fedora 1 上,您可以使用以下命令安装它们:
dnf debuginfo-install python
Run Code Online (Sandbox Code Playgroud)
然后将gdb附加到运行脚本并运行以下命令:
[user@host ~]$ pidof python2
9219
[user@host ~]$ gdb python2 9219
GNU gdb (GDB) Fedora 7.7.1-13.fc20
...
0x00007fa934278780 in __read_nocancel () at ../sysdeps/unix/syscall-template.S:81
81 T_PSEUDO (SYSCALL_SYMBOL, SYSCALL_NAME, SYSCALL_NARGS)
(gdb) call fflush(stdout)
$1 = 0
(gdb) call setvbuf(stdout, 0, 2, 0)
$2 = 0
(gdb) quit
A debugging session is active.
Inferior 1 [process 9219] will be detached.
Quit anyway? (y or n) y
Detaching from program: /usr/bin/python2, process 9219
Run Code Online (Sandbox Code Playgroud)
这将刷新标准输出并禁用缓冲。在2从setvbuf呼叫的价值_IONBF我的系统上。你需要找出你身上有什么(一个grep _IONBF /usr/include/stdio.h应该可以解决问题)。
根据我在 CPython 2.7PyFile_SetBufSize和PyFile_WriteStringCPython 2.7的实现中所看到的,它应该可以很好地工作,但我不能做出任何保证。
1 Fedora 包含一种特殊类型的 RPM,称为debuginfo rpms。这些自动创建的 RPM 包含来自程序文件的调试信息,但已移至外部文件中。