使用golang获取远程服务器中运行的进程的pid

问题描述 投票:0回答:1

我正在尝试获取在远程服务器中使用 ssh 会话执行的命令的 pid。但 pid 为空。有这方面的帮助吗?

这是我的程序..

    func (c *SSHClient) RunCommandWithContext(ctx context.Context, command string) (string, error) {
    if c.Client == nil {
        return "", errors.New("SSH client is not connected")
    }

    session, err := c.Client.NewSession()
    if err != nil {
        return "", err
    }
    defer session.Close()

    var stdoutBuf bytes.Buffer
    session.Stdout = &stdoutBuf

    // Channel to signal completion
    done := make(chan error, 1)

    // Run the command and get the PID
    var stdout, stderr bytes.Buffer
    session.Stdout = &stdout
    session.Stderr = &stderr

    go func() {
        done <- session.Run(command)
    }()

    // Extract the PID from the output
    output := strings.TrimSpace(stdout.String())
    fmt.Println("Output:", output) <-- this is coming empty
    pid, err := strconv.Atoi(output)
    fmt.Println("PID:", pid) <--- I need the pid of the command I am executing remoting.
    fmt.Println("Error:", err)
    if err != nil {
        log.Fatalf("Failed to parse PID: %v", err)
    }
    log.Printf("Started command with PID %d\n", pid)

    ticker := time.NewTicker(2 * time.Second)
    defer ticker.Stop()
    for {
        select {
        case <-ctx.Done():
            // Context timeout
            if err := session.Signal(ssh.SIGKILL); err != nil {
                return "", fmt.Errorf("failed to kill process: %w", err)
            }
            return "", ctx.Err()
        case <-ticker.C:
            log.Println("Checking command status...")
            if !isProcessRunning(session, pid) {
                log.Println("Command finished successfully")
                printLogs(stdout.String(), stderr.String())
                return "", nil
            }
        case err := <-done:
            // Command completed
            if err != nil {
                return "", err
            }
            return stdoutBuf.String(), nil
        }
    }
    return "", nil
}

// This program asynchronously checks if the command has completed or not
func isProcessRunning(session *ssh.Session, pid int) bool { 
    command := fmt.Sprintf("ps -p %d", pid)
    if err := session.Run(command); err != nil {
        return false
    }
    // Run the command and get the PID
    var stdout, stderr bytes.Buffer
    session.Stdout = &stdout
    session.Stderr = &stderr
    output := strings.TrimSpace(stdout.String())
    return strings.Contains(output, strconv.Itoa(pid))
}
go ssh
1个回答
0
投票

实际上,在 pid 的帮助下,我需要检查命令是否已成功完成或以某种失败状态退出。请让我知道如何使用会话本身来实现这一点

我不确定你打算如何从 PID 进入其退出状态。 但无论如何也没有必要这样做! ssh.Session 本身支持这一点。

如果命令不成功,

ssh.Session.Run会返回错误:

如果命令运行,复制 stdin、stdout 和 stderr 没有问题,并且以零退出状态退出,则返回的错误为零。

如果远程服务器未发送退出状态,则返回 *ExitMissingError 类型的错误。如果命令未成功完成或被信号中断,则错误类型为 *ExitError。 I/O 问题可能会返回其他错误类型。

如果您从

Run()
收到错误,您可以执行类型断言或
errors.As
来查看它是否是
*ssh.ExitError
。 如果是,您就知道该命令失败并可以根据需要进行处理。

如果您得到

*ssh.ExitError
,您可以根据需要确定退出代码。 更有用的是在任何错误消息中包含 stderr 缓冲区,因为它将包含命令可能提供的有关失败原因的任何解释。

然后您可以删除股票代码和

ps
逻辑等等。 在任何语言中,您都不需要轮询来查看子流程是否已结束;总有办法等待。

© www.soinside.com 2019 - 2024. All rights reserved.