【问题标题】:How can a process intercept stdout and stderr of another process on Linux?一个进程如何拦截Linux上另一个进程的stdout和stderr?
【发布时间】:2010-09-19 23:11:33
【问题描述】:

我有一些脚本本应该停止运行,但会一直挂着。有什么方法可以让我以一种可读的方式弄清楚他们向 STDOUT 和 STDERR 写入的内容吗?

例如,我尝试过这样做:

$ tail -f /proc/(pid)/fd/1

但这并没有真正起作用。无论如何,这是一个很长的镜头。

还有其他想法吗?

strace 本身就非常冗长且无法阅读。

注意:我对他们的输出感兴趣,对其他任何东西都不感兴趣。我有能力自己弄清楚其他事情;这个问题只关注在启动它之后访问正在运行的进程的stdout和stderr。

【问题讨论】:

  • 当我的目标程序写入管道时,这对我有用,

标签: linux stdout


【解决方案1】:

由于我不允许编辑 Jauco 的答案,我将给出对我有用的完整答案(Russell 的页面依赖于未保证的行为,如果您关闭 STDOUT 的文件描述符 1,则下一个 creat调用将打开 FD 1。

所以,像这样运行一个简单的无限脚本:

import time

while True:
    print 'test'
    time.sleep(1)

保存到test.py,运行

$ python test.py

获取 PID:

$ ps auxw | grep test.py

现在,附上gdb

$ gdb -p (pid)

然后使用fd 魔法:

(gdb) call creat("/tmp/stdout", 0600)
$1 = 3
(gdb) call dup2(3, 1)
$2 = 1

现在您可以tail /tmp/stdout 并查看以前转到 STDOUT 的输出。

【讨论】:

  • 无论如何 dup2 解决方案更好,但是(关于 creat 返回 1)只要使用 0 并且没有其他人创建文件描述符,它就不是没有保证的:UNIX 保证返回最低的可用 fd 编号。
  • 这真的行不通。当您运行所有这些命令时,任何有用的 stdout 可能已经丢失到以太网中,并且此方法不会追溯捕获任何已打印的内容。
【解决方案2】:

有几个新的实用程序封装了“gdb 方法”并添加了一些额外的功能。我现在使用的那个叫做“reptyr”(“Re-PTY-er”)。除了抓取 STDERR/STDOUT 之外,它实际上会改变进程的控制终端(即使它之前没有连接到终端)。

最好的用途是启动一个屏幕会话,并使用它将正在运行的进程重新附加到屏幕内的终端,这样您就可以安全地与其分离并稍后再回来。

它被打包在流行的发行版上(例如:'apt-get install reptyr')。

http://onethingwell.org/post/2924103615/reptyr

【讨论】:

    【解决方案3】:

    GDB 方法似乎更好,但您也可以使用 strace 来做到这一点:

    $ strace -p <PID> -e write=1 -s 1024 -o file
    

    通过strace 的手册页:

       -e write=set
                   Perform a full hexadecimal and ASCII dump of all the
                   data written to file descriptors listed in the spec-
                   ified  set.  For example, to see all output activity
                   on file descriptors 3 and 5 use -e write=3,5.   Note
                   that  this is independent from the normal tracing of
                   the write(2) system call which is controlled by  the
                   option -e trace=write.
    

    这比你需要的多一些(十六进制部分),但你可以很容易地sed 输出。

    【讨论】:

      【解决方案4】:

      我不确定它是否适合你,但我不久前读过一页描述method that uses gdb

      【讨论】:

        【解决方案5】:

        我使用 strace 并将十六进制输出解码为明文:

        PID=some_process_id
        sudo strace -f -e trace=write -e verbose=none -e write=1,2 -q -p $PID -o "| grep '^ |' | cut -c11-60 | sed -e 's/ //g' | xxd -r -p"
        

        我从其他答案中结合了这个命令。

        【讨论】:

          【解决方案6】:

          strace 仅使用-ewrite(而不是=1 后缀)的输出要少得多。而且它比 IMO 的 GDB 方法简单一些。

          我用它来查看现有 MythTV 编码作业的进度(sudo,因为我不拥有编码过程):

          $ ps -aef | grep -i handbrake
          mythtv   25089 25085 99 16:01 ?        00:53:43 /usr/bin/HandBrakeCLI -i /var/lib/mythtv/recordings/1061_20111230122900.mpg -o /var/lib/mythtv/recordings/1061_20111230122900.mp4 -e x264 -b 1500 -E faac -B 256 -R 48 -w 720
          jward    25293 20229  0 16:30 pts/1    00:00:00 grep --color=auto -i handbr
          
          $ sudo strace -ewrite -p 25089
          Process 25089 attached - interrupt to quit
          write(1, "\rEncoding: task 1 of 1, 70.75 % "..., 73) = 73
          write(1, "\rEncoding: task 1 of 1, 70.76 % "..., 73) = 73
          write(1, "\rEncoding: task 1 of 1, 70.77 % "..., 73) = 73
          write(1, "\rEncoding: task 1 of 1, 70.78 % "..., 73) = 73^C
          

          【讨论】:

            【解决方案7】:

            您可以使用重定向 (https://github.com/jerome-pouiller/reredirect/)。

            类型

            reredirect -m FILE PID
            

            输出(标准和错误)将写入 FILE。

            reredirect README 还解释了如何恢复进程的原始状态,如何重定向到另一个命令或仅重定向 stdout 或 stderr。

            【讨论】:

              【解决方案8】:

              你没有说明你的操作系统,但我要试一试,说“Linux”。

              查看正在写入 stderr 和 stdout 的内容可能无济于事。如果有用,您可以在启动脚本之前使用 tee(1) 来获取 stderr 和 stdout 的副本。

              您可以使用 ps(1) 来查找 wchan。这告诉您进程正在等待什么。如果您查看 strace 输出,您可以忽略大部分输出并识别最后一个(阻塞的)系统调用。如果是对文件句柄的操作,您可以在输出中倒退并识别底层对象(文件、套接字、管道等)。从那里答案可能很清楚。

              您还可以向进程发送一个信号,使其转储内核,然后使用调试器和内核文件获取堆栈跟踪。

              【讨论】:

                猜你喜欢
                • 2016-09-04
                • 1970-01-01
                • 2015-10-12
                • 2012-07-05
                • 2015-03-16
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多