代码之家  ›  专栏  ›  技术社区  ›  Thomas Vander Stichele

一个进程如何拦截Linux上另一个进程的stdout和stderr?

  •  39
  • Thomas Vander Stichele  · 技术社区  · 16 年前

    我有一些剧本本该停止运行,但却一直流传下去。

    有什么方法可以让我以一种可读的方式知道它们在向stdout和stderr写入什么吗?

    例如,我试着去做

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

    但这不太管用。不管怎样,这是一个长期的尝试。

    还有其他想法吗?Strace本身就非常冗长,无法阅读。

    注:我是 只有 对他们的产出感兴趣,而不是其他任何东西。我能够自己解决其他问题;这个问题只关注获取正在运行的进程的stdout和stderr的访问权。 之后 启动它。

    8 回复  |  直到 10 年前
        1
  •  7
  •   Jauco    16 年前

    我不确定它是否适合你,但我读了一页前一段时间描述 method that uses gdb

        2
  •  41
  •   Thomas Vander Stichele    16 年前

    由于不允许我编辑小渊的答案,我将给出对我有用的完整答案(Russell的页面依赖于无担保的行为,如果您关闭fd 1进行stdout,下一个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
    

    现在,您可以跟踪/tmp/stdout并查看用于转到stdout的输出。

        3
  •  9
  •   itsadok    12 年前

    有几个新的实用程序总结了“gdb方法”,并添加了一些额外的修饰。我现在使用的是“reptyr”(“re pty er”)。除了抓取stderr/stdout之外,它还将实际更改进程的控制终端(即使它以前没有连接到终端)。

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

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

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

        4
  •  8
  •   Daniel Lopez    13 年前

    gdb方法似乎更好,但您也可以使用strace来实现这一点:

    strace-p-e write=1-s 1024-o文件

       -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.
    

    这会打印出比您需要的(十六进制部分)更多的内容,但您可以轻松地打印出来。

        5
  •  4
  •   Lari Hotari    12 年前

    我使用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
  •  2
  •   Jeff Ward    13 年前

    strace使用just-ewrite(而不是=1后缀)输出的结果要少得多。它比gdb方法,imo简单一点。

    我使用它来查看现有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
  •  2
  •   Jérôme Pouiller    10 年前

    你可以用REREDIRECT( https://github.com/jerome-pouiller/reredirect/ )

    类型

    reredirect -m FILE PID
    

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

    重定向 README 还解释了如何恢复进程的原始状态、如何重定向到其他命令或只重定向stdout或stderr。

        8
  •  1
  •   janm    16 年前

    您不需要声明您的操作系统,但我将尝试一下并说“Linux”。

    查看正在写入stderr和stdout的内容可能没有帮助。如果有用,可以在启动脚本之前使用tee(1)获取stderr和stdout的副本。

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

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