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

发布于 2024-07-08 07:22:31 字数 370 浏览 20 评论 0原文

我有一些应该停止运行的脚本,但它们却永远存在。 有什么方法可以让我以可读的方式弄清楚他们正在向 STDOUT 和 STDERR 写入什么内容?

例如,我尝试这样做:

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

但这并没有真正起作用。 无论如何,这是一个远景。

还有其他想法吗?

strace 本身就非常冗长且不可读。

注意:我对他们的输出感兴趣,对其他任何东西都不感兴趣。 其他的事情我有能力自己解决; 这个问题仅关注于启动正在运行的进程后获取其stdout 和stderr 的访问权限。

I have some scripts that ought to have stopped running but hang around forever. Is there some way I can figure out what they're writing to STDOUT and STDERR in a readable way?

I tried, for example, to do:

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

but that doesn't really work. It was a long shot anyway.

Any other ideas?

strace on its own is quite verbose and unreadable for seeing this.

Note: I am only interested in their output, not in anything else. I'm capable of figuring out the other things on my own; this question is only focused on getting access to stdout and stderr of the running process after starting it.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

安静被遗忘 2024-07-15 07:22:31

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

因此,运行一个简单的无尽脚本,如下所示:

import time

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

将其保存到 test.py,运行

$ python test.py

Get the PID:

$ ps auxw | grep test.py

Now, Attach gdb:

$ gdb -p (pid)

并执行 fd 魔法:

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

现在您可以 tail /tmp/stdout 并查看过去用于 STDOUT 的输出。

Since I'm not allowed to edit Jauco's answer, I'll give the full answer that worked for me (Russell's page relies on un-guaranteed behaviour that, if you close file descriptor 1 for STDOUT, the next creat call will open FD 1.

So, run a simple endless script like this:

import time

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

Save it to test.py, run with

$ python test.py

Get the PID:

$ ps auxw | grep test.py

Now, attach gdb:

$ gdb -p (pid)

and do the fd magic:

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

Now you can tail /tmp/stdout and see the output that used to go to STDOUT.

硬不硬你别怂 2024-07-15 07:22:31

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

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

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

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

There's several new utilities that wrap up the "gdb method" and add some extra touches. The one I use now is called "reptyr" ("Re-PTY-er"). In addition to grabbing STDERR/STDOUT, it will actually change the controlling terminal of a process (even if it wasn't previously attached to a terminal).

The best use of this is to start up a screen session, and use it to reattach a running process to the terminal within screen so you can safely detach from it and come back later.

It's packaged on popular distros (Ex: 'apt-get install reptyr').

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

夜未央樱花落 2024-07-15 07:22:31

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 轻松解决这个问题。

GDB method seems better, but you can do this with strace, too:

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

Via the man page for 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.

This prints out somewhat more than you need (the hexadecimal part), but you can sed that out easily.

流年已逝 2024-07-15 07:22:31

我不确定它是否适合您,但我不久前读过一页描述 使用 gdb 的方法

I'm not sure if it will work for you, but I read a page a while back describing a method that uses gdb

猥︴琐丶欲为 2024-07-15 07:22:31

我使用 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"

我将此命令与其他答案结合起来。

I used strace and de-coded the hex output to clear text:

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"

I combined this command from other answers.

烟燃烟灭 2024-07-15 07:22:31

仅使用 -ewrite(而不是 =1 后缀),strace 的输出要少得多。 而且它比 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

strace outputs a lot less with just -ewrite (and not the =1 suffix). And it's a bit simpler than the GDB method, IMO.

I used it to see the progress of an existing MythTV encoding job (sudo because I don't own the encoding process):

$ 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
蒗幽 2024-07-15 07:22:31

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

类型

reredirect -m FILE PID

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

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

You can use reredirect (https://github.com/jerome-pouiller/reredirect/).

Type

reredirect -m FILE PID

and outputs (standard and error) will be written in FILE.

reredirect README also explains how to restore original state of process, how to redirect to another command or to redirect only stdout or stderr.

夜夜流光相皎洁 2024-07-15 07:22:31

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

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

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

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

You don't state your operating system, but I'm going to take a stab and say "Linux".

Seeing what is being written to stderr and stdout is probably not going to help. If it is useful, you could use tee(1) before you start the script to take a copy of stderr and stdout.

You can use ps(1) to look for wchan. This tells you what the process is waiting for. If you look at the strace output, you can ignore the bulk of the output and identify the last (blocked) system call. If it is an operation on a file handle, you can go backwards in the output and identify the underlying object (file, socket, pipe, etc.) From there the answer is likely to be clear.

You can also send the process a signal that causes it to dump core, and then use the debugger and the core file to get a stack trace.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文