[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

作者:cjdty

出处:https://www.cnblogs.com/cjdty/p/18603109

版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。

posted @   Startu  阅读(124)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
more_horiz
keyboard_arrow_up light_mode palette
选择主题
点击右上角即可分享
微信分享提示