从已经运行的脚本重定向stderr


14

我已经运行脚本好几天了。我将stdout重定向到$HOME/mylog,但没有重定向stderr,因为我认为上面没有任何内容。突然,成千上万的线路开始在stderr上运行,所以我暂停了工作。$HOME/myerr从现在开始,是否有一种方法可以将stderr重定向到,而无需重新启动脚本?

我在盒子上有sudo访问权限,它是OSX。

也许有一些使用工具陷阱的东西?

我不会丢失脚本到目前为止所做的工作,并从头开始重新启动它。有没有一种方法可以在磁盘上“转储内存中的对象”,冻结程序,编辑变量(例如文件描述符)并使用新的上下文恢复


Answers:


12

我认为将相关解释器的过程附加到gdb是可能的。我用这个perl单线尝试过

 perl -e 'do { print "x\n"; sleep(1) } while(1)'

而且它可以工作,但不幸的是,不能与类似的bash脚本一起使用。


首先,您必须确定要捕获其输出的该进程的PID。然后从gdb另一个终端启动并执行以下gdb命令

attach PID
call close(2)
call open("/abs/olu/te/path/filename", 65, 384)
detach PID

之后,将写入的所有数据stderr重定向到/abs/olu/te/path/filename,因为

  • attach PID 将进程附加到gdb并停止它
  • call close(2)关闭stderr进程stdout的文件描述符(文件描述符为1)
  • call open(...) 打开一个新文件,并为新创建的filedescriptor取最低的未使用整数,然后
  • detach PID 继续进行

至少在我的机器上。前两行与POSIX兼容,但第三行不兼容。

open第三行中的第二个和第三个参数记录在中man 2 open。在我的情况下65意味着open应该创建文件并打开文件,即只写即O_WRONLY | O_CREAT(在中定义fcntl.h)。第三个参数告诉open创建具有用户读写权限的文件,即S_IWUSR | S_IRUSR(在中定义sys/stat.h)。因此,也许您必须自己在计算机上找到合适的值。


如此出色的工作非常出色...
Robottinosino 2012年

8

这是一个粗略的答案,我希望其他人可以做得更好,但是如果没有其他想法浮出水面,请附加gdb并强制该过程进行一些系统调用:

(gdb) attach 12345 # target PID
(gdb) p close(2)
(gdb) p open("errfile", O_WRONLY)
(gdb) c

好漂亮 我不知道gdb可以做到这一点。有什么方法可以将其强制为特定的文件描述符编号?例如说FD 1是否未使用,而open()抓取FD 1?还是只需dup()要打几次电话?
Patrick

p open("errfile", O_WRONLY)在您的机器上真的有效吗?
user1146332 2012年

你可以坚持的p dup2(xxx, 2),然后p close(xxx)在那里xxx是的返回值open。这是一件棘手的事情,最好不要在长时间运行的过程中使用这些命令,除非您确定别无选择。
艾伦·库里

@ user1146332它在我尝试时确实有用,因为我曾经用过它/dev/nullerrfile所以我不需要O_CREAT。而O_WRONLY作为一个宏,无论扩展与否取决于是否GDB停止该过程在一个行,其中调试符号都可以和宏定义。使用gdb将代码注入到进程中是很危险的,没有人会在不理解它们的情况下复制这些命令。
艾伦·库里

@AlanCurry如果可以使用常规调试信息,我认为gdb不会扩展宏。您必须使用特殊标志编译源代码(请参见此处)。除此之外,系统上的任意可执行文件都包含调试信息是非常罕见的(让信息单独扩展为宏信息)。但是我同意您的意见,通常不建议使用代码注入,但是在某些情况下您可能会受益。
user1146332
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.