简体   繁体   English

如何检查进程ID(PID)是否存在

[英]How to check if a process id (PID) exists

In a bash script, I want to do the following (in pseudo-code):在 bash 脚本中,我想执行以下操作(在伪代码中):

if [ a process exists with $PID ]; then

    kill $PID 

fi

What's the appropriate expression for the conditional statement?条件语句的适当表达式是什么?

The best way is:最好的办法是:

if ps -p $PID > /dev/null
then
   echo "$PID is running"
   # Do something knowing the pid exists, i.e. the process with $PID is running
fi

The problem with:问题在于:

kill -0 $PID

is the exit code will be non-zero even if the pid is running and you dont have permission to kill it.即使pid正在运行并且您无权杀死它,退出代码也将是非零的。 For example:例如:

kill -0 1

and

kill -0 $non-running-pid

have an indistinguishable (non-zero) exit code for a normal user, but the init process (PID 1) is certainly running.对于普通用户,有一个无法区分的(非零)退出代码,但 init 进程(PID 1)肯定正在运行。

DISCUSSION讨论

The answers discussing kill and race conditions are exactly right if the body of the test is a "kill".如果测试的主体是“kill”,那么讨论 kill 和 Race conditions 的答案是完全正确的。 I came looking for the general " how do you test for a PID existence in bash ".我来寻找一般的“你如何测试 bash 中的 PID 存在”。

The /proc method is interesting, but in some sense breaks the spirit of the "ps" command abstraction, ie you dont need to go looking in /proc because what if Linus decides to call the "exe" file something else? /proc 方法很有趣,但从某种意义上说,它打破了“ps”命令抽象的精神,也就是说,您不需要去查看 /proc,因为如果 Linus 决定将“exe”文件称为别的东西怎么办?

To check for the existence of a process, use要检查进程是否存在,请使用

kill -0 $pid

But just as @unwind said, if you're going to kill it anyway, just但正如@unwind 所说,如果你无论如何要杀死它,就

kill $pid

or you will have a race condition.否则你会遇到竞争条件。

If you want to ignore the text output of kill and do something based on the exit code, you can如果你想忽略kill的文本输出并根据退出代码做一些事情,你可以

if ! kill $pid > /dev/null 2>&1; then
    echo "Could not send SIGTERM to process $pid" >&2
fi
if [ -n "$PID" -a -e /proc/$PID ]; then
    echo "process exists"
fi

or或者

if [ -n "$(ps -p $PID -o pid=)" ]

In the latter form, -o pid= is an output format to display only the process ID column with no header.在后一种形式中, -o pid=是一种输出格式,仅显示没有标题的进程 ID 列。 The quotes are necessary for non-empty string operator -n to give valid result.非空字符串运算符-n需要引号才能给出有效结果。

ps command with -p $PID can do this:带有-p $PID ps命令可以执行此操作:

$ ps -p 3531
  PID TTY          TIME CMD
 3531 ?        00:03:07 emacs

You have two ways:你有两种方法:

Lets start by looking for a specific application in my laptop:让我们首先在我的笔记本电脑中寻找一个特定的应用程序:

[root@pinky:~]# ps fax | grep mozilla
 3358 ?        S      0:00  \_ /bin/sh /usr/lib/firefox-3.5/run-mozilla.sh /usr/lib/firefox-3.5/firefox
16198 pts/2    S+     0:00              \_ grep mozilla

All examples now will look for PID 3358.现在所有示例都将查找 PID 3358。

First way : Run "ps aux" and grep for the PID in the second column.第一种方法:在第二列中为 PID 运行“ps aux”和 grep。 In this example I look for firefox, and then for it's PID:在这个例子中,我寻找 firefox,然后寻找它的 PID:

[root@pinky:~]# ps aux | awk '{print $2 }' | grep 3358
3358

So your code will be:所以你的代码将是:

if [ ps aux | awk '{print $2 }' | grep -q $PID 2> /dev/null ]; then
    kill $PID 
fi

Second way : Just look for something in the /proc/$PID directory.第二种方式:只需在/proc/$PID目录中查找内容即可。 I am using "exe" in this example, but you can use anything else.我在这个例子中使用了“exe”,但你可以使用其他任何东西。

[root@pinky:~]# ls -l /proc/3358/exe 
lrwxrwxrwx. 1 elcuco elcuco 0 2010-06-15 12:33 /proc/3358/exe -> /bin/bash

So your code will be:所以你的代码将是:

if [ -f /proc/$PID/exe ]; then
    kill $PID 
fi

BTW: whats wrong with kill -9 $PID || true顺便说一句: kill -9 $PID || true有什么问题kill -9 $PID || true kill -9 $PID || true ? kill -9 $PID || true吗?


EDIT:编辑:

After thinking about it for a few months.. (about 24...) the original idea I gave here is a nice hack, but highly unportable.在考虑了几个月之后......(大约 24 ......)我在这里给出的最初想法是一个很好的黑客,但非常不可移植。 While it teaches a few implementation details of Linux, it will fail to work on Mac, Solaris or *BSD.虽然它讲授了 Linux 的一些实现细节,但它无法在 Mac、Solaris 或 *BSD 上运行。 It may even fail on future Linux kernels.它甚至可能在未来的 Linux 内核上失败。 Please - use "ps" as described in other responses.请 - 使用“ps”,如其他回复中所述。

It seems like you want好像你想要

wait $PID

which will return when $pid finishes.这将在$pid完成时返回。

Otherwise you can use否则你可以使用

ps -p $PID

to check if the process is still alive (this is more effective than kill -0 $pid because it will work even if you don't own the pid).检查进程是否还活着(这比kill -0 $pid更有效,因为即使您不拥有 pid 它也能工作)。

I think that is a bad solution, that opens up for race conditions.我认为这是一个糟糕的解决方案,它为竞争条件开辟了道路。 What if the process dies between your test and your call to kill?如果进程在您的测试和您的 kill 调用之间终止了怎么办? Then kill will fail.那么kill就会失败。 So why not just try the kill in all cases, and check its return value to find out how it went?那么为什么不在所有情况下都尝试 kill 并检查其返回值以了解它是如何进行的呢?

code below checks if my process is running, if so do nothing. 下面的代码检查我的进程是否正在运行,如果是,则不执行任

let's check new messages from Amazon SQS every hour only and only if the process is not running. 让我们每小时检查来自Amazon SQS的新消息,并且仅在进程未运行时才检查。

#!/bin/bash
PID=$(ps aux | grep '/usr/bin/python2.7 manage.py SES__boto3_sqs_read' | grep -v grep | awk '{print $2}')
if [[ -z $PID ]]; then
    /usr/bin/python2.7 /home/brian/djcode/proyectoONE/manage.py SES__boto3_sqs_read
else
    echo "do nothing, just smile =)"
fi
exit $?

By pid :通过pid

pgrep [pid] >/dev/null

By name :名称

pgrep -u [user] -x [name] >/dev/null

" -x " means "exact match". -x ”表示“完全匹配”。

For example in GNU/Linux you can use:例如在 GNU/Linux 中,您可以使用:

Pid=$(pidof `process_name`)

if [ $Pid > 0 ]; then

   do something
else

   do something
fi 

Or something like或者类似的东西

Pin=$(ps -A | grep name | awk 'print $4}')
echo $PIN

and that shows you the name of the app, just the name without ID.这会显示应用程序的名称,只是没有 ID 的名称。

here i store the PID in a file called .pid (which is kind of like /run/...) and only execute the script if not already being executed.在这里,我将 PID 存储在一个名为 .pid 的文件中(类似于 /run/...),并且仅在尚未执行的情况下才执行脚本。

#!/bin/bash
if [ -f .pid ]; then
  read pid < .pid
  echo $pid
  ps -p $pid > /dev/null
  r=$?
  if [ $r -eq 0 ]; then
    echo "$pid is currently running, not executing $0 twice, exiting now..."
    exit 1
  fi
fi

echo $$ > .pid

# do things here

rm .pid

note: there is a race condition as it does not check how that pid is called.注意:存在竞争条件,因为它不检查该 pid 的调用方式。 if the system is rebooted and .pid exists but is used by a different application this might lead 'unforeseen consequences'.如果系统重新启动并且 .pid 存在但被不同的应用程序使用,这可能会导致“不可预见的后果”。

This answer has been rewritten since the downvote.自反对票以来,此答案已被重写。

I learned from and upvoted @FDS's answer here , because it is good and correct.从@FDS's answer here 中学习并投票赞成,因为它很好而且正确。 But, here's a form I find easier to read and understand.但是,这是一个我觉得更容易阅读和理解的表格。

So, here is my preferred version:所以,这是我的首选版本:

Explanation:解释:

  1. The "$?" "$?" part means "the exit or return code from the previous command". part 表示“上一个命令的退出或返回代码”。
  2. The ps --pid "$pid" command returns exit code 0 if the specified PID ( "$pid" ) is running, and some other number if not.如果指定的 PID ( "$pid" ) 正在运行,则ps --pid "$pid"命令返回退出代码0 ,否则返回其他数字。
  3. Doing > /dev/null discards all output printed to stdout , since we don't want to see it.执行> /dev/null会丢弃打印到stdout的所有输出,因为我们不想看到它。 Rather, all we want is the exit code ( "$?" ) from the ps --pid "$pid" command to see if that PID is running.相反,我们想要的只是ps --pid "$pid"命令的退出代码 ( "$?" ),以查看该 PID 是否正在运行。 More specifically, using > /dev/null redirects stdout output to the /dev/null pseudofile, whose purpose is to discard all incoming input.更具体地说,使用> /dev/nullstdout输出重定向到/dev/null伪文件,其目的是丢弃所有传入的输入。
pid=1234
ps --pid "$pid" > /dev/null
if [ "$?" -eq 0 ]; then
    echo "PID $pid exists and is running."
fi

Running shellcheck path/to/this_script.sh tells me I should actually do it the other way (as @FDS shows) to avoid redundancy.运行shellcheck path/to/this_script.sh告诉我实际上应该以另一种方式(如@FDS 所示)来避免冗余。 See the shellcheck output here:在此处查看shellcheck输出:

eRCaGuy_hello_world/bash$ shellcheck check_if_pid_exists.sh 

In check_if_pid_exists.sh line 46:
if [ "$?" -eq 0 ]; then
     ^--^ SC2181: Check exit code directly with e.g. 'if mycmd;', not indirectly with $?.

For more information:
  https://www.shellcheck.net/wiki/SC2181 -- Check exit code directly with e.g...

Notice especially this part:特别注意这部分:

SC2181: Check exit code directly with eg ' if mycmd; SC2181:直接使用例如' if mycmd; ', not indirectly with $? ',不是间接用$? . .

See the full description for this error code here: https://github.com/koalaman/shellcheck/wiki/SC2181 .在此处查看此错误代码的完整描述: https ://github.com/koalaman/shellcheck/wiki/SC2181。

So, shellcheck recommends this form instead:所以, shellcheck推荐这种形式:

pid=1234
if ps --pid "$pid" > /dev/null; then
    echo "PID $pid exists and is running."
fi

If you want to adjust to doing it that way, go for it.如果你想适应那样做,那就去做吧。 But, if you'd rather do it my way because you consider my way easier to read and understand, as I do, then you can optionally disable that shellcheck warning by adding # shellcheck disable=SC2181 above that line, like this:但是,如果你宁愿按照我的方式做,因为你认为我的方式更容易阅读和理解,就像我一样,那么你可以选择通过在该行上方添加# shellcheck disable=SC2181来禁用该shellcheck警告,如下所示:

My final and preferred answer我的最终和首选答案

ps --pid "$pid" >/dev/null
# shellcheck disable=SC2181
if [ "$?" -eq 0 ]; then
    echo "PID $pid exists and is running."
else
    echo "PID $pid does NOT exist."
fi

The key takeaway here, however, is to never insert any command, not even an echo or print statement, between the command being checked ( ps in this case) and checking the error code with "$?"然而,这里的关键点是永远不要在被检查的命令(在这种情况下为ps )和用"$?"检查错误代码之间插入任何命令,甚至是echo显或print语句。 , or else checking the error code will accidentally check the error code from the latest command, such as the inserted echo or print statement , instead of from the command of interest ( ps in our case)! , 否则检查错误代码会意外地从最新命令中检查错误代码,例如插入的echoprint语句,而不是从感兴趣的命令(在我们的例子中为ps )!

That's the main reason shellcheck recommends what they do: they want to make sure you're checking the error code of the correct command.这就是shellcheck推荐他们做什么的主要原因:他们想确保您检查的是正确命令的错误代码。

Other than that, it's just a pedantic opinion-based-discussion-equivalent to the argument in C about how you should check for NULL (null pointer) values:除此之外,它只是一个迂腐的基于意见的讨论,相当于 C 中关于如何检查NULL (空指针)值的论点:

// The way preferred by pedantic people who don't want to "be redundant" with 
// an "unnecessary" `== NULL` check:
if (!some_ptr)
{
    printf("ERROR: null ptr.\n");
    return;
}

// Versus the more-readable and understandable way which I prefer to use
// whenever my peers will approve it without a fight or long argument
if (some_ptr == NULL)       // in C
// if (some_ptr == nullptr) // in C++
{
    printf("ERROR: null ptr.\n");
    return;
}

// Note: I just want to get my code merged and move on with life, so if they
// won't easily approve my preferred version above, I'll switch to the other,
// more-pedantic version of code to try to get a quick approval so I can be
// more productive. 
// There are few things more discouraging than being blocked over
// silly "pedantry" when your code is correct, bug-free, well-written, and does
// what it says it does.

So, just as which way you choose to check for NULL values (null ptrs) in C is purely a matter of taste, which way in bash you choose to check for error codes/return codes is also purely a matter of taste.因此,正如您选择在 C 中选择哪种方式检查NULL值(null ptrs)纯粹是个人喜好问题一样,在 bash 中选择哪种方式检查错误代码/返回代码也纯粹是个人喜好问题。 Currently, I prefer the version above I have marked as "My final and preferred answer".目前,我更喜欢上面我标记为“我的最终和首选答案”的版本。

Anyway, here is a full, runnable program无论如何,这是一个完整的,可运行的程序

check_if_pid_exists.sh from my eRCaGuy_hello_world repo: check_if_pid_exists.sh来自我的eRCaGuy_hello_world 存储库:

#!/usr/bin/env bash

pid=1234

if [ "$#" -gt 0 ]; then
    # At least 1 argument was passed in, so assume it is the PID
    pid="$1"
fi

# Try to print the process (`ps`) information for this PID. Send it to
# /dev/null, however, so we don't actually have to look at it. We just want
# the return code, `$?`, which will be 0 if the process exists and some other
# number if not.
ps --pid "$pid" > /dev/null
# shellcheck disable=SC2181
if [ "$?" -eq 0 ]; then
    echo "PID $pid exists and is running."
else
    echo "PID $pid does NOT exist."
fi

Sample run calls and output:示例运行调用和输出:

eRCaGuy_hello_world/bash$ ./check_if_pid_exists.sh 28876
PID 28876 exists and is running.

eRCaGuy_hello_world/bash$ ./check_if_pid_exists.sh
PID 1234 does NOT exist.

eRCaGuy_hello_world/bash$ ./check_if_pid_exists.sh 5678
PID 5678 does NOT exist.

You can find valid PIDs (Process IDs) to send to my script by first running ps aux and choosing a PID to pass to it.您可以通过首先运行ps aux并选择要传递给它的 PID 来找到要发送到我的脚本的有效 PID(进程 ID)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM