如何重定向一个正在执行的程序的标准输出
如何在Linux系统中更改一个正在执行的程序的标准输出重定向到其他文件?事情的场景是这样的,由于同事的疏忽,忘了关闭一个springboot微服务的控制台日志输出,而这个进程启动后又会把标准输出和标准错误输出写到一个process.log的日志文件中,由于控制台信息输出太多,导致长时间日志磁盘占用过大,这时候又来了一个骚操作,直接把这个日志文件删除掉了?。
直接删除文件这个肯定是没用的,通过rm删除文件将会从文件系统的目录结构上解除链接(unlink),然而如果文件是被打开的(有进程正在使用),那么进程将仍然可以读取该文件,磁盘空间也一直被占用,这样就会导致删除了文件,但是磁盘空间却未被释放,大量的文件句柄无法释放。
执行 lsof|grep [pid]|grep deleted
查看,确实出现了文件句柄泄露?
然后查看对应进程的文件文件描述符(fd:file descriptor)ls -l /proc/[pid]/fd
可以看到文件描述符1和2都指向了被删除的日志文件
那么如何解决这个问题呢?杀掉进程是最简单的方法,但如果不重启呢?从上面fd表上我们看到1和2指向删除文件,那么我们能不能更改这个指向,重定向到/dev/null丢掉输出呢❔
答案是有的,主要依赖于Linux 的 close()、open()、dup2()函数。(open函数也可用creat函数替换)
close函数用于关闭一个已打开的文件,函数原型如下:
1 |
int close(int filedes); |
open函数可以打开或创建一个文件,函数原型如下:
1 |
int open(const char *pathname, int flags); |
dup2函数可以复制一个文件的描述符,函数原型如下:
1 |
int dup2( int oldfd, int targetfd ) |
简单来说,close关闭一个文件描述符,open打开一个文件并返回文件描述符,dup2将目标文件描述符变成源文件描述符的一个复制,即两个文件描述符都指向了源文件描述符指向的文件上去。所以我们可以关闭掉标准输出fd1,然后open /dev/null获得一个新的文件描述符,再将fd1指向/dev/null,这样就完成了重定向一个标准输出。
OK,我们用GDB尝试一下,首先gdb -p [pid]
进入gdb调试?
1 |
(gdb) p close(1) |
这样就完成标准输出重定向到/dev/null,标准错误输出依此类推
再次查看对应进程的文件描述符列表,1和2都成功指向了/dev/null,并且文件句柄也被释放掉✌
不仅仅适用于这个场景,这个方法也可以把一个忘记了nohup启动的进程放置到后台运行等等其他方面。
共有 0 条评论