[linux] 获取重定向到/dev/null的进程标准输出
一般来说,linux上后台运行的程序都会写类似于 ./foo 1>/dev/null 2>&1
以此实现不输出任何东西,但是如果需要用到标准输出用来调试,此时就会很要命
对于这样的程序,通过命令 ls -l /proc/<pid>/fd/
可以看到 1 已经指向/dev/null
了。
如果想要获取输出,可以通过以下步骤
gdb attach <pid>
call (int)dup2((int)open("/root/foo_stdout.log", 1089, 0777), 1)
- 退出gdb即可
此时可以看到指定的log文件已经创建了,通过ls -l /proc/<pid>/fd/
可以看到标准输出已经重定向到指定文件了。
原理就是通过gdb向程序插入代码并执行,dup2可以实现类似重定向的效果。如果需要重定向标准错误,把dup2的第二个参数改为2应该就可以了。
open的参数1089是 O_WRONLY | O_CREAT | O_APPEND 的结果,所以对log文件是追加效果,具体可参考:https://stackoverflow.com/questions/72071279/attaching-to-a-process-and-call-dup2-on-aarch64
之后可以通过如下脚本实现这样的功能,第一个参数是pid,第二个参数为指定文件
#!/bin/bash
# 脚本用于修改正在运行进程的标准输出和错误输出,依赖gdb,请保证gdb可用
# 第一个参数是进程pid,你可以使用pgrep <进程名>获取,第二个参数为输出文件,第三个参数为要修改的输出流,2为标准错误,1为标准输出,不提供这个参数默认为1
# 例如 ./notnull.sh 11223 /root/loader.log 2 会将11223进程的标准错误重定向到loader.log文件
if [ "$#" -lt 2 ]; then
echo "Usage: $0 <PID> <output_log> [fd]"
exit 1
fi
PID=$1
FILENAME=$2
if [ "$#" -eq 3 ]; then
FD=$3
else
FD=1
fi
if [[ "$FILENAME" != /* ]]; then
if command -v realpath >/dev/null 2>&1; then
FILENAME=$(realpath "$FILENAME")
elif command -v readlink >/dev/null 2>&1; then
FILENAME=$(readlink -f "$FILENAME")
else
echo "Error: realpath or readlink command is not available."
exit 1
fi
fi
if ! kill -0 $PID > /dev/null 2>&1; then
echo "Error: Process with PID $PID does not exist."
exit 1
fi
gdb -ex "attach $PID" -ex "call (int)dup2((int)open(\"$FILENAME\", 1089, 0777), $FD)" -batch
分类:
Linux
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库