如何重定向已在运行的进程的输出

She*_*oss 136 linux bash

通常我会开始像这样的命令

longcommand &;
Run Code Online (Sandbox Code Playgroud)

我知道你可以通过做类似的事情来重定向它

longcommand > /dev/null;
Run Code Online (Sandbox Code Playgroud)

例如,摆脱输出或

longcommand 2>&1 > output.log
Run Code Online (Sandbox Code Playgroud)

捕获输出.

但我有时会忘记,并且想知道是否有办法在事后捕获或重定向.

longcommand
ctrl-z
bg 2>&1 > /dev/null
Run Code Online (Sandbox Code Playgroud)

或类似的东西,所以我可以继续使用终端没有在终端上弹出的消息.

use*_*875 123

请参阅从正在运行的进程重定向输出.

首先,我cat > foo1在一个会话中运行该命令,并测试stdin中的数据是否已复制到该文件中.然后在另一个会话中,我重定向输出.

首先找到过程的PID:

$ ps aux | grep cat
rjc 6760 0.0 0.0 1580 376 pts/5 S+ 15:31 0:00 cat
Run Code Online (Sandbox Code Playgroud)

现在检查它已打开的文件句柄:

$ ls -l /proc/6760/fd
total 3
lrwx—— 1 rjc rjc 64 Feb 27 15:32 0 -> /dev/pts/5
l-wx—— 1 rjc rjc 64 Feb 27 15:32 1 -> /tmp/foo1
lrwx—— 1 rjc rjc 64 Feb 27 15:32 2 -> /dev/pts/5
Run Code Online (Sandbox Code Playgroud)

现在运行GDB:

$ gdb -p 6760 /bin/cat
GNU gdb 6.4.90-debian

[license stuff snipped]

Attaching to program: /bin/cat, process 6760

[snip other stuff that's not interesting now]

(gdb) p close(1)
$1 = 0
(gdb) p creat("/tmp/foo3", 0600)
$2 = 1
(gdb) q
The program is running. Quit anyway (and detach it)? (y or n) y
Detaching from program: /bin/cat, process 6760
Run Code Online (Sandbox Code Playgroud)

pGDB中的命令会打印一个表达式的值,一个表达式可以是一个函数来调用,它可以是一个系统调用...所以我执行一个close()系统调用并传递文件句柄1,然后我执行一个creat()系统调用来打开一个新的文件.结果creat()为1表示它替换了以前的文件句柄.如果我想为stdout和stderr使用相同的文件,或者如果我想用其他数字替换文件句柄,那么我需要调用dup2()系统调用来实现该结果.

对于这个例子,我选择使用creat()而不是open()因为参数较少.标志的C宏不能从GDB中使用(它不使用C头)所以我必须读取头文件才能发现这一点 - 这样做并不难,但需要更多时间.请注意,0600是具有读/写访问权限的所有者的八进制权限,而该组和其他人无权访问.它也可以使用0作为该参数,稍后在该文件上运行chmod.

之后我验证了结果:

ls -l /proc/6760/fd/
total 3
lrwx—— 1 rjc rjc 64 2008-02-27 15:32 0 -> /dev/pts/5
l-wx—— 1 rjc rjc 64 2008-02-27 15:32 1 -> /tmp/foo3 <====
lrwx—— 1 rjc rjc 64 2008-02-27 15:32 2 -> /dev/pts/5
Run Code Online (Sandbox Code Playgroud)

键入更多数据以cat导致/tmp/foo3附加到的文件.

如果要关闭原始会话,则需要关闭它的所有文件句柄,打开一个可以作为控制tty的新设备,然后调用setsid().

  • 总是更好地复制它的要点,而不仅仅是链接. (29认同)
  • 如果我每次使用你帖子中的链接都可以给你一个Up Vote,你至少会进入前100名.顺便问一下,你是不是觉得离开userXXX联盟的冲动? (5认同)
  • 要点:使用`gdb`附加到正在运行的进程,然后执行'p close(1)'和'p creat("/ tmp/foo3",0600)'重定向STDOUT,然后断开gdb,同时让程序保持运行.一个聪明的伎俩! (4认同)
  • 此解决方案有效,但我必须以root身份使用gdb,否则进程无法附加. (2认同)
  • `creat`调用如何知道它必须覆盖文件句柄`1`即`stdout`? (2认同)
  • @iggy我想它只是使用了第一个免费句柄(而且`1`刚刚关闭,所以显然是免费的,也是第一个). (2认同)

Jér*_*ler 19

您也可以使用reredirect(https://github.com/jerome-pouiller/reredirect/)来完成.

类型

reredirect -m FILE PID
Run Code Online (Sandbox Code Playgroud)

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

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

(reredirect似乎具有与Dupx在另一个答案中描述的相同的功能,但是,它不依赖于Gdb).


小智 15

Dupx

Dupx是一个简单的*nix实用程序,用于重定向已经运行的进程的标准输出/输入/错误.

动机

我经常发现自己处于这样一种情况,即我通过SSH在远程系统上启动的进程花费的时间比我预期的要长得多.我需要打破SSH连接,但如果我这样做,如果它试图在stdout上写一些东西/破坏管道的错误,那么进程就会死掉.我希望我能用^ Z暂停这个过程,然后做一个

bg %1 >/tmp/stdout 2>/tmp/stderr 
Run Code Online (Sandbox Code Playgroud)

不幸的是,这不起作用(在我知道的炮弹中).

http://www.isi.edu/~yuri/dupx/


lem*_*eze 7

屏幕

如果进程在屏幕会话中运行,您可以使用screen的log命令将该窗口的输出记录到文件中:

切换到脚本的窗口,C-a H进行记录.
现在你可以 :

$ tail -f screenlog.2 | grep whatever
Run Code Online (Sandbox Code Playgroud)

从屏幕的手册页:

log [on | off]

开始/停止将当前窗口的输出写入窗口默认目录中的文件"screenlog.n",其中n是当前窗口的编号.可以使用'logfile'命令更改此文件名.如果未给出参数,则切换日志记录的状态.会话日志将附加到文件的先前内容(如果已存在).回滚历史记录的当前内容和内容不包括在会话日志中.默认为"关闭".

我确信tmux也有类似的东西.