检查进程是否存在的go方式

huangapple go评论116阅读模式
英文:

Check if a process exists in go way

问题

如果我有一个进程的PID,使用os.FindProcess来测试进程是否存在是否足够?我的意思是,如果它返回err,我可以假设进程已经终止(或被杀死)吗?

编辑:

我刚刚写了一个围绕kill -s 0(旧式bash进程测试)的包装函数。这个方法没有任何问题,但如果有其他使用Go库解决这个问题的方法,我会很高兴:

func checkPid(pid int) bool {
    out, err := exec.Command("kill", "-s", "0", strconv.Itoa(pid)).CombinedOutput()
    if err != nil {
        log.Println(err)
    }

    if string(out) == "" {
        return true // pid存在
    }
    return false
}
英文:

If I have the PID of a process, is os.FindProcess enough to test for the existing of the process? I mean if it returns err can I assume that it's terminated (or killed)?

Edit:

I've just wrote a wrapper function around kill -s 0 (old-style bash process testing). This works without any problem, but I'm still happy if there is other solutions (done with go libraries) to this problem.:

func checkPid(pid int) bool {
	out, err := exec.Command("kill", "-s", "0", strconv.Itoa(pid)).CombinedOutput()
	if err != nil {
		log.Println(err)
	}

	if string(out) == "" {
		return true // pid exist
	}
	return false
}

答案1

得分: 45

这是查看进程是否存活的传统Unix方式 - 发送一个信号0(就像你在bash示例中所做的那样)。

来自kill(2)

> 如果sig为0,则不发送信号,但仍然执行错误检查;这可以用于检查进程ID或进程组ID的存在。

并且翻译成Go语言:

package main

import (
	"fmt"
	"log"
	"os"
	"strconv"
	"syscall"
)

func main() {
	for _, p := range os.Args[1:] {
		pid, err := strconv.ParseInt(p, 10, 64)
		if err != nil {
			log.Fatal(err)
		}
		process, err := os.FindProcess(int(pid))
		if err != nil {
			fmt.Printf("无法找到进程:%s\n", err)
		} else {
			err := process.Signal(syscall.Signal(0))
			fmt.Printf("在进程ID %d 上的process.Signal返回:%v\n", pid, err)
		}

	}
}

当你运行它时,你会得到以下结果,显示进程123已经停止,进程1仍在运行但不属于你,进程12606仍在运行且属于你。

$ ./kill 1 $$ 123
在进程ID 1 上的process.Signal返回:操作不允许
在进程ID 12606 上的process.Signal返回:<nil>
在进程ID 123 上的process.Signal返回:没有这个进程
英文:

Here is the traditional unix way to see if a process is alive - send it a signal of 0 (like you did with your bash example).

From kill(2):

> If sig is 0, then no signal is sent, but error checking is still per‐
> formed; this can be used to check for the existence of a process ID or
> process group ID.

And translated into Go

package main

import (
	&quot;fmt&quot;
	&quot;log&quot;
	&quot;os&quot;
	&quot;strconv&quot;
	&quot;syscall&quot;
)

func main() {
	for _, p := range os.Args[1:] {
		pid, err := strconv.ParseInt(p, 10, 64)
		if err != nil {
			log.Fatal(err)
		}
		process, err := os.FindProcess(int(pid))
		if err != nil {
			fmt.Printf(&quot;Failed to find process: %s\n&quot;, err)
		} else {
			err := process.Signal(syscall.Signal(0))
			fmt.Printf(&quot;process.Signal on pid %d returned: %v\n&quot;, pid, err)
		}

	}
}

When you run it you get this, showing that process 123 is dead, process 1 is alive but not owned by you and process 12606 is alive and owned by you.

$ ./kill 1 $$ 123
process.Signal on pid 1 returned: operation not permitted
process.Signal on pid 12606 returned: &lt;nil&gt;
process.Signal on pid 123 returned: no such process

答案2

得分: 6

在类Unix系统(如Linux、FreeBSD等)上,os.FindProcess永远不会返回错误。我不知道在Windows上会发生什么。这意味着在尝试使用*os.Process进行某些操作之前,您无法确定PID是否正确。

您可以在这里查看代码here

英文:

On unix like systems (linux, freebsd, etc) os.FindProcess will never return an error. I don't know what happens on Windows. This means you won't know if the PID is correct until you try to use the *os.Process for something.

You can look at the code here.

答案3

得分: 5

你也可以直接使用syscall.Kill。这样可以减少代码量。

killErr := syscall.Kill(pid, syscall.Signal(0))
procExists := killErr == nil

英文:

You can also just use syscall.Kill. It amounts to less code.

killErr := syscall.Kill(pid, syscall.Signal(0))
procExists := killErr == nil

答案4

得分: 2

如果在系统中找不到先前已知的pid(不确定go函数),这意味着进程肯定已经终止并已加入(在Unix上,使用wait调用)。

但反过来并不一定成立。仅仅因为一个pid存在,并不能保证它是之前的同一个进程。例如,在标准Linux中只有65535个有效的pid,并且当发生回绕时它们可以被重新使用。然而,如果您经常进行检查,对于实际目的来说,您不需要关心这个问题(只要错误的新进程的pid不是安全漏洞或其他关键问题,有人可能会故意触发以进行恶意目的)。

相关链接(以及右侧的相关问题):

英文:

If a previously known pid is not found in the system (not sure of go functions), it means process has definitely terminated and has been joined (on Unix, with wait call) too.

But other way around is not necessarily true. Just because a pid exists, it does not quarantee it is same process as before. There are only 65535 valid pids in standard Linux for example, and they can get re-used when there is a wrap-around. However, if you check reasonably often, for practical purposes you don't need to care about this (as long as pid of wrong new process being found is not a security vulnerability or something else critical, which somebody might try to trigger intentionally for malicious purposes).

Related links (and Related questions on their right columns):

答案5

得分: 2

所有到目前为止的答案都是不完整的实现。请参考https://github.com/shirou/gopsutil/blob/c141152a7b8f59b63e060fa8450f5cd5e7196dfb/process/process_posix.go#L73,这是一个更完整的实现(内联复制)

	func PidExists(pid int32) (bool, error) {
	    if pid <= 0 {
		    return false, fmt.Errorf("invalid pid %v", pid)
	    }
	    proc, err := os.FindProcess(int(pid))
	    if err != nil {
		    return false, err
	    }
	    err = proc.Signal(syscall.Signal(0))
	    if err == nil {
		    return true, nil
	    }
	    if err.Error() == "os: process already finished" {
		    return false, nil
	    }
	    errno, ok := err.(syscall.Errno)
	    if !ok {
		    return false, err
	    }
	    switch errno {
	    case syscall.ESRCH:
		    return false, nil
	    case syscall.EPERM:
		    return true, nil
	    }
	    return false, err
    }
英文:

All the answers so far are incomplete implementations. See https://github.com/shirou/gopsutil/blob/c141152a7b8f59b63e060fa8450f5cd5e7196dfb/process/process_posix.go#L73 for a more complete implementation (copied inline)

	func PidExists(pid int32) (bool, error) {
	    if pid &lt;= 0 {
		    return false, fmt.Errorf(&quot;invalid pid %v&quot;, pid)
	    }
	    proc, err := os.FindProcess(int(pid))
	    if err != nil {
		    return false, err
	    }
	    err = proc.Signal(syscall.Signal(0))
	    if err == nil {
		    return true, nil
	    }
	    if err.Error() == &quot;os: process already finished&quot; {
		    return false, nil
	    }
	    errno, ok := err.(syscall.Errno)
	    if !ok {
		    return false, err
	    }
	    switch errno {
	    case syscall.ESRCH:
		    return false, nil
	    case syscall.EPERM:
		    return true, nil
	    }
	    return false, err
    }

答案6

得分: 2

这里是一种在Windows上使用Golang检查进程是否存在/运行的方法。

我们执行以下命令:

TASKLIST /V /NH /FI "PID eq 23232"

可能会返回以下结果:

INFO: No tasks are running which match the specified criteria.

或者如果找到了:

Image Name                     PID Session Name        Session#    Mem Usage Status          User Name                                              CPU Time Window Title                                                         
========================= ======== ================ =========== ============ =============== ================================================== ============ ========================================================================
chrome.exe                   23232 Console                    1     42,472 K Unknown         THANOS\MARVEL                                       0:00:00 N/A                                         

这里有一个利用这些信息的函数。

func isProcessRunning(pid int) bool {
	cmd := exec.Command("TASKLIST", "/FI", fmt.Sprintf("PID eq %d", pid))
	result, err := cmd.Output()
	if err != nil {
		return false
	}
	return !bytes.Contains(result, []byte("No tasks are running"))
}

最好的是,你还可以通过其他参数找到进程:

ImageName   eq, ne                  Image Name String
PID         eq, ne, gt, lt, ge, le  Process ID, A Positive integer.
Session     eq, ne, gt, lt, ge, le  Any valid session number.
SessionName eq, ne                  String
Status      eq, ne                  RUNNING | NOT RESPONDING | UNKNOWN
CPUTime     eq, ne, gt, lt, ge, le  Time hh:mm:ss
MemUsage    eq, ne, gt, lt, ge, le  Memory usage in KB, specify a valid integer.
Username    eq, ne                  User name ([Domain\]User).
Services    eq, ne                  Service Name String
Windowtitle eq, ne                  Window Title String
Modules     eq, ne                  DLL Name String
英文:

Here is one way of how to check if a process exists/running with Golang on Windows.

We execute the command:

TASKLIST /V /NH /FI &quot;PID eq 23232&quot;

Which can return either:

INFO: No tasks are running which match the specified criteria.

Or if found:

Image Name                     PID Session Name        Session#    Mem Usage Status          User Name                                              CPU Time Window Title                                                         
========================= ======== ================ =========== ============ =============== ================================================== ============ ========================================================================
chrome.exe                   23232 Console                    1     42,472 K Unknown         THANOS\MARVEL                                       0:00:00 N/A                                         

Here is a function that takes advantage of this information.

func isProcessRunning(pid int) bool {
	cmd := exec.Command(&quot;TASKLIST&quot;, &quot;/FI&quot;, fmt.Sprintf(&quot;PID eq %d&quot;, pid))
	result, err := cmd.Output()
	if err != nil {
		return false
	}
	return !bytes.Contains(result, []byte(&quot;No tasks are running&quot;))
}

The best thing about this is you can find the process by other parameters too:

ImageName   eq, ne                  Image Name String
PID         eq, ne, gt, lt, ge, le  Process ID, A Positive integer.
Session     eq, ne, gt, lt, ge, le  Any valid session number.
SessionName eq, ne                  String
Status      eq, ne                  RUNNING | NOT RESPONDING | UNKNOWN
CPUTime     eq, ne, gt, lt, ge, le  Time hh:mm:ss
MemUsage    eq, ne, gt, lt, ge, le  Memory usage in KB, specify a valid integer.
Username    eq, ne                  User name ([Domain\]User).
Services    eq, ne                  Service Name String
Windowtitle eq, ne                  Window Title String
Modules     eq, ne                  DLL Name String

答案7

得分: 1

在Windows上,检查os.FindProcess()的结果似乎足以检查进程是否正在运行。

func isProcessRunning(pid int) bool {
    _, err = os.FindProcess(pid)
    if err != nil {
        return false
    }
    if runtime.GOOS == "windows" {
        return true
    }
    return false // 进一步检查其他系统是否为Windows的支持在这里不被支持
}
英文:

On Windows checking the result of os.FindProcess() seems to be enough to check if process is running.

func isProcessRunning(pid int) bool {
	_, err = os.FindProcess(pid)
	if err != nil {
		return false
	}
	if runtime.GOOS == &quot;windows&quot; {
		return true
	}
	return false // further checking for other systems then Windows is not supported here
}

答案8

得分: -1

func CheckProcessLife(pid int){
cmd,_ := exec.Command("tasklist","/FI", "PID eq " + strconv.Itoa(pid)).Output()
output := string(cmd[:])
splitOutp := strings.Split(output, " ")
if !(splitOutp1 == "no") {
time.Sleep(500 * time.Millisecond)
fmt.Println("进程正在运行...")
CheckProcessLife(pid)
}else{
fmt.Println("进程已停止运行。")
}
}

您可以通过进程的PID或直接通过进程名称来检查进程是否正在运行,只需更改此行代码:

cmd,_ := exec.Command("tasklist","/FI", "IMAGENAME eq yourprocessname.exe").Output()

英文:

After searching for a few hours, the correct answer to know if a process is running on Windows is the following:

func CheckProcessLife(pid int){
    cmd,_ := exec.Command(&quot;tasklist&quot;,&quot;/FI&quot;, &quot;PID eq &quot; + strconv.Itoa(pid)).Output()
    output := string(cmd[:])
    splitOutp := strings.Split(output, &quot; &quot;)
    if !(splitOutp[1] == &quot;no&quot;) {
	    time.Sleep(500 * time.Millisecond)
	    fmt.Println(&quot;Process is running...&quot;)
	    CheckProcessLife(pid)
    }else{
	    fmt.Println(&quot;Process is no longer running.&quot;)
    }
}

You can check if the process is running with his PID or directly with his name, only change this line:

cmd,_ := exec.Command(&quot;tasklist&quot;,&quot;/FI&quot;, &quot;IMAGENAME eq yourprocessname.exe&quot;).Output()

huangapple
  • 本文由 发表于 2013年3月4日 22:44:06
  • 转载请务必保留本文链接:https://go.coder-hub.com/15204162.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定