【发布时间】:2020-11-20 18:05:55
【问题描述】:
我有一个进程在服务器上运行,由于某种原因我的客户端系统重新启动,所以我使用终端再次登录到服务器。
进程按预期运行,但终端上不断提示的进程状态由于显而易见的原因消失了(因为我现在在另一个终端上)。
有什么办法可以让我将正在运行的进程的 STDOUT 带到当前终端?
谢谢。
【问题讨论】:
我有一个进程在服务器上运行,由于某种原因我的客户端系统重新启动,所以我使用终端再次登录到服务器。
进程按预期运行,但终端上不断提示的进程状态由于显而易见的原因消失了(因为我现在在另一个终端上)。
有什么办法可以让我将正在运行的进程的 STDOUT 带到当前终端?
谢谢。
【问题讨论】:
首先我在一个会话中运行命令
cat > foo1并测试来自标准输入的数据是否被复制到文件中。然后在另一个会话中我重定向输出。首先找到进程的PID:
$ ps aux | grep cat rjc 6760 0.0 0.0 1580 376 pts/5 S+ 15:31 0:00 cat现在检查它打开的文件句柄:
$ 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现在运行 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 6760GDB中的
p命令会打印一个表达式的值,一个表达式可以是要调用的函数,也可以是系统调用……所以我执行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在
cat中输入更多数据会导致文件/tmp/foo3被附加到。如果要关闭原始会话,则需要关闭它的所有文件句柄,打开一个可以作为控制 tty 的新设备,然后调用
setsid()。
【讨论】:
使用以下脚本从任何进程中更改标准。
此脚本附加 gdb 并更改进程的文件描述符,分离 gdb 并继续进程。
用法:
如果没有指定输出文件,则输出重定向到当前终端
#!/bin/sh
filename=`tty`
if [ -z "$2" ]; then
filename=`tty`
else
file_abs_path=`echo $2 | grep "^/.*"`
if [ -z "$file_abs_path" ]; then
filename="`pwd`/$2"
else
filename=$2
fi
fi
original_terminal=`file /proc/$1/fd/1 | grep -o "symbolic.*" | grep -o "\/[^ ']*"`
echo "Original stdout: $original_terminal"
echo "" > $1.temp
echo "p fileno(fopen("\"$filename\"", "\""w"\""))" >> $1.temp
echo 'call dup2($1, 1)' >> $1.temp
echo 'call dup2($1, 2)' >> $1.temp
echo "q" >> $1.temp
gdb -p $1 -x $1.temp < /dev/null >& /dev/null
echo "New stdout: $filename"
rm -rf $1.temp
【讨论】: