Golang如何获取进程状态(运行/停止)

Golang如何获取进程状态(运行/停止) 如何获取进程状态(在Linux虚拟机上),已知程序名称和某些参数。我知道如果知道PID是可以做到的,但我需要通过名称和参数来实现。

一些指导方向就足够了。

谢谢

// 代码示例保留原样
3 回复

关于使用"ps aux"命令获取进程运行状态(如果进程未运行则无法获取)的方法如何?

更多关于Golang如何获取进程状态(运行/停止)的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


在Unix系统中,PID是每个进程的唯一标识符。通过PID可以获取进程的相关信息。

Linux系统拥有一个/proc文件系统,其中包含进程信息。/proc目录列表会显示许多以数字命名的目录,每个目录对应一个PID。在这些目录中存在包含各类信息的文件,包括:

/proc/<PID>/comm - 命令名称
以及
/proc/<PID>/cmdline - 命令行参数

您可以通过搜索这些文件来找到包含目标命令名称/参数的PID。

详细内容请参阅proc(5)手册页:

http://manpages.ubuntu.com/manpages/xenial/man5/proc.5.html

要检查您的代码,可以使用

pidof <command_name>

该命令会打印指定名称命令的PID。

在Linux环境下,你可以通过解析/proc文件系统来获取进程状态。以下是一个完整的实现示例,通过进程名称和参数来匹配进程并获取其状态:

package main

import (
    "bufio"
    "fmt"
    "os"
    "path/filepath"
    "strings"
)

// ProcessStatus 表示进程状态
type ProcessStatus struct {
    PID     string
    Name    string
    Status  string // 运行状态
    Command string // 完整命令行
}

// GetProcessStatusByNameAndArgs 通过进程名和参数获取进程状态
func GetProcessStatusByNameAndArgs(processName string, args []string) ([]ProcessStatus, error) {
    var results []ProcessStatus
    
    // 遍历 /proc 目录下的所有数字目录(PID目录)
    entries, err := os.ReadDir("/proc")
    if err != nil {
        return nil, err
    }

    for _, entry := range entries {
        if !entry.IsDir() {
            continue
        }

        pid := entry.Name()
        // 检查是否为数字目录(PID)
        if !isNumeric(pid) {
            continue
        }

        // 读取进程状态文件
        statusFile := filepath.Join("/proc", pid, "status")
        status, err := parseStatusFile(statusFile)
        if err != nil {
            continue
        }

        // 读取命令行文件
        cmdlineFile := filepath.Join("/proc", pid, "cmdline")
        cmdline, err := parseCmdlineFile(cmdlineFile)
        if err != nil {
            continue
        }

        // 检查进程名和参数是否匹配
        if matchesProcess(processName, args, cmdline) {
            results = append(results, ProcessStatus{
                PID:     pid,
                Name:    status["Name"],
                Status:  status["State"],
                Command: cmdline,
            })
        }
    }

    return results, nil
}

// parseStatusFile 解析 /proc/[pid]/status 文件
func parseStatusFile(filename string) (map[string]string, error) {
    file, err := os.Open(filename)
    if err != nil {
        return nil, err
    }
    defer file.Close()

    status := make(map[string]string)
    scanner := bufio.NewScanner(file)
    
    for scanner.Scan() {
        line := scanner.Text()
        parts := strings.SplitN(line, ":", 2)
        if len(parts) == 2 {
            key := strings.TrimSpace(parts[0])
            value := strings.TrimSpace(parts[1])
            status[key] = value
        }
    }

    return status, scanner.Err()
}

// parseCmdlineFile 解析 /proc/[pid]/cmdline 文件
func parseCmdlineFile(filename string) (string, error) {
    content, err := os.ReadFile(filename)
    if err != nil {
        return "", err
    }
    
    // cmdline 文件使用 null 字节分隔参数
    cmdline := strings.ReplaceAll(string(content), "\x00", " ")
    return strings.TrimSpace(cmdline), nil
}

// matchesProcess 检查进程名和参数是否匹配
func matchesProcess(processName string, expectedArgs []string, actualCmdline string) bool {
    // 检查进程名是否匹配
    if !strings.Contains(actualCmdline, processName) {
        return false
    }

    // 检查所有参数是否都存在
    for _, arg := range expectedArgs {
        if !strings.Contains(actualCmdline, arg) {
            return false
        }
    }

    return true
}

// isNumeric 检查字符串是否为数字
func isNumeric(s string) bool {
    for _, c := range s {
        if c < '0' || c > '9' {
            return false
        }
    }
    return s != ""
}

// 使用示例
func main() {
    // 查找包含特定参数的程序
    processName := "myapp"
    args := []string{"--config", "/etc/myapp.conf"}
    
    processes, err := GetProcessStatusByNameAndArgs(processName, args)
    if err != nil {
        fmt.Printf("Error: %v\n", err)
        return
    }

    if len(processes) == 0 {
        fmt.Println("No matching processes found")
        return
    }

    for _, proc := range processes {
        fmt.Printf("PID: %s, Name: %s, Status: %s\n", proc.PID, proc.Name, proc.Status)
        fmt.Printf("Command: %s\n\n", proc.Command)
    }
}

这个实现的主要功能:

  1. 遍历/proc目录:扫描所有进程目录
  2. 解析状态文件:从/proc/[pid]/status获取进程状态信息
  3. 解析命令行:从/proc/[pid]/cmdline获取完整的命令行参数
  4. 匹配条件:根据进程名和参数进行匹配
  5. 返回结果:返回匹配进程的状态信息

进程状态字段说明:

  • R:运行中 (Running)
  • S:睡眠中 (Sleeping)
  • D:不可中断睡眠
  • Z:僵尸进程
  • T:已停止 (Stopped)

使用示例:

// 查找nginx进程,包含特定配置文件
processes, err := GetProcessStatusByNameAndArgs("nginx", []string{"-c", "/etc/nginx/nginx.conf"})

这种方法不需要预先知道PID,完全基于进程名称和命令行参数进行匹配。

回到顶部