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

发布于 2024-09-05 17:01:22 字数 145 浏览 3 评论 0原文

在 bash 脚本中,我想要执行以下操作(以伪代码形式):

if [ a process exists with $PID ]; then

    kill $PID 

fi

条件语句的适当表达式是什么?

In a bash script, I want to do the following (in pseudo-code):

if [ a process exists with $PID ]; then

    kill $PID 

fi

What's the appropriate expression for the conditional statement?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(11

你的背包 2024-09-12 17:01:22

最好的方法是:

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

kill -0 $PID 的问题是,即使进程正在运行并且您没有杀死它的权限,退出代码也将不为零。例如:

kill -0 $known_running_pid

并且

kill -0 $non_running_pid

具有非零退出代码,对于普通用户来说无法区分,但其中一个是假设运行的,而另一个则不是。


AnrDaemon 提供的部分相关附加信息:init 进程(PID 1)肯定在所有 Linux 计算机上运行,但并非所有 POSIX 系统都是 Linux。不保证 PID 1 存在:

kill -0 1 
-bash: kill: (1) - No such process … 

讨论

如果测试的主体是“kill”,那么讨论kill 和竞争条件的答案是完全正确的。我来寻找一般性的“如何测试 bash 中是否存在 PID”。

/proc 方法很有趣,但在某种意义上破坏了 ps 命令抽象的精神,即您不需要去查找 /proc< /code> 因为如果 Linus 决定调用 exe 文件其他内容怎么办?

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 that the exit code will be non-zero even if the process is running and you don't have permission to kill it. For example:

kill -0 $known_running_pid

and

kill -0 $non_running_pid

have a non-zero exit codes that are indistinguishable for a normal user, but one of them is by assumption running, while the other is not.


Partly related, additional info provided by AnrDaemon: The init process (PID 1) is certainly running on all Linux machines, but not all POSIX systems are Linux. PID 1 is not guaranteed to exist there:

kill -0 1 
-bash: kill: (1) - No such process … 

DISCUSSION

The answers discussing kill and race conditions are exactly right if the body of the test is a "kill". I came looking for the general "how do you test for a PID existence in bash".

The /proc method is interesting, but in some sense breaks the spirit of the ps command abstraction, i.e. you don't need to go looking in /proc because what if Linus decides to call the exe file something else?

浅浅 2024-09-12 17:01:22

要检查进程是否存在,请使用

kill -0 $pid

But just as @unwind said,如果您希望它在任何情况下终止,然后就

kill $pid

否则,您将遇到竞争条件,该进程可能在第一个 kill -0 之后消失。

如果您想忽略 kill 的文本输出并根据退出代码执行某些操作,您可以

if ! kill $pid > /dev/null 2>&1; then
    echo "Could not send SIGTERM to process $pid" >&2
fi

To check for the existence of a process, use

kill -0 $pid

But just as @unwind said, if you want it to terminate in any case, then just

kill $pid

Otherwise you will have a race condition, where the process might have disappeared after the first kill -0.

If you want to ignore the text output of kill and do something based on the exit code, you can

if ! kill $pid > /dev/null 2>&1; then
    echo "Could not send SIGTERM to process $pid" >&2
fi
凉世弥音 2024-09-12 17:01:22

在实现 procfs 接口的系统(例如 Linux)上,您只需检查 /proc/ $PID 存在:

if test -d /proc/"$PID"/; then
    echo "process exists"
fi

否则您可以使用 ps 程序:

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

在后一种形式中,-o pid= 是一种输出格式,仅显示进程 ID 列没有标题。对于非空字符串运算符,引号是必需的 -n 给出有效结果。

On systems that implement procfs interface such as Linux, you can just check if /proc/$PID exists:

if test -d /proc/"$PID"/; then
    echo "process exists"
fi

otherwise you can use ps program:

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. The quotes are necessary for non-empty string operator -n to give valid result.

新一帅帅 2024-09-12 17:01:22

ps 命令与 -p $PID 可以做到这一点:

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

ps command with -p $PID can do this:

$ ps -p 3531
  PID TTY          TIME CMD
 3531 ?        00:03:07 emacs
苦行僧 2024-09-12 17:01:22

您有两种方法:

首先在我的笔记本电脑中查找特定应用程序:

[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

现在所有示例都将查找 PID 3358

第一种方法:针对第二列中的PID运行ps auxgrep。在此示例中,我查找 firefox,然后查找它的 PID

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

因此您的代码将是:

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

第二种方式:只需在/proc/$PID 目录。我在本例中使用 exe,但您可以使用其他任何东西。

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

所以你的代码将是:

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

BTW: kill -9 $PID || 有什么问题吗?真的吗?


编辑:

经过几个月的思考......(大约24......)我在这里给出的最初想法是一个很好的技巧,但非常不可移植。虽然它教授了 Linux 的一些实现细节,但它无法在 Mac、Solaris 或 *BSD 上运行。它甚至可能在未来的 Linux 内核上失败。请 - 按照其他中所述使用“ps”回复

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.

First way: Run ps aux and grep for the PID in the second column. In this example I look for firefox, and then for it's 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. I am using exe in this example, but you can use anything else.

[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 ?


EDIT:

After thinking about it for a few months.. (about 24...) the original idea I gave here is a nice hack, but highly unportable. While it teaches a few implementation details of Linux, it will fail to work on Mac, Solaris or *BSD. It may even fail on future Linux kernels. Please - use "ps" as described in other responses.

情绪操控生活 2024-09-12 17:01:22

我认为这是一个糟糕的解决方案,会引发竞争条件。如果进程在测试和调用终止之间终止怎么办?那么kill就会失败。那么为什么不尝试在所有情况下执行kill,并检查它的返回值以了解它是如何进行的呢?

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? Then kill will fail. So why not just try the kill in all cases, and check its return value to find out how it went?

究竟谁懂我的在乎 2024-09-12 17:01:22

看起来你想要

wait $PID

$pid 完成时返回。

否则,您可以使用它

ps -p $PID

来检查进程是否仍然存在(这比 kill -0 $pid 更有效,因为即使您不拥有 pid,它也能工作)。

It seems like you want

wait $PID

which will return when $pid finishes.

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).

两相知 2024-09-12 17:01:22

例如,在 GNU/Linux 中,您可以使用:

Pid=$(pidof `process_name`)

if [ $Pid > 0 ]; then

   do something
else

   do something
fi 

或类似的内容

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

,它会显示应用程序的名称,只是不带 ID 的名称。

For example in GNU/Linux you can use:

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.

沉默的熊 2024-09-12 17:01:22

在这里学习并赞成@FDS的答案,因为它很好而且正确。但是,我发现这是一个更容易阅读和理解的表格。

所以,这是我的首选版本:

说明:

  1. "$?" 部分表示“上一个命令的退出或返回代码”。
  2. 如果指定的 PID ("$pid") 正在运行,并且某些情况下,ps --pid "$pid" 命令将返回退出代码 0如果没有则其他号码。
  3. > /dev/null 丢弃所有打印到 stdout 的输出,因为我们不想看到它。相反,我们想要的只是 ps --pid "$pid" 命令的退出代码 ("$?"),以查看该 PID 是否正在运行。更具体地说,使用 > /dev/nullstdout 输出重定向到 /dev/null 伪文件,其目的是丢弃所有传入的输入。
pid=1234
ps --pid "$pid" > /dev/null
if [ "$?" -eq 0 ]; then
    echo "PID $pid exists and is running."
fi

运行 shellcheck path/to/this_script.sh 告诉我实际上应该以其他方式执行此操作(如 @FDS 所示)以避免冗余。请参阅此处的 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...

特别注意这部分:

SC2181:直接使用“if mycmd;”检查退出代码,而不是使用 $? 间接检查。

请在此处查看此错误代码的完整描述:https://github.com/koalaman/shellcheck/维基/SC2181

因此,shellcheck 建议采用这种形式:

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

如果您想适应这种方式,那就去做吧。但是,如果您愿意按照我的方式进行操作,因为您认为我的方式更容易阅读和理解,就像我一样,那么您可以选择通过添加 # shellcheck disable= 来禁用该 shellcheck 警告。 SC2181 位于该行上方,如下所示:

我的最终首选答案

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

然而,这里的关键要点是永远不要插入任何命令,甚至不包括echo 或 print 语句,在被检查的命令(在本例中为 ps)和使用 "$?" 检查错误代码之间,或者否则检查错误代码将意外地检查错误代码来自最新命令,例如插入的 echoprint 语句,而不是来自感兴趣的命令(在我们的例子中是 ps)!

这就是 shellcheck 推荐他们所做的事情的主要原因:他们希望确保您正在检查错误代码的正确命令。

除此之外,它只是一个迂腐的基于意见的讨论,相当于 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.

所以,只是在 C 中选择哪种方式检查 NULL 值(null ptrs)纯粹是一个品味问题,在 bash 中选择哪种方式检查错误代码/返回代码也纯粹是一个问题品尝。目前,我更喜欢上面我标记为“我的最终和首选答案”的版本。

无论如何,这是一个完整的、可运行的程序

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

示例运行调用和输出:

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.

您可以通过首先运行 ps aux 并选择要传递给它的 PID 来找到要发送到我的脚本的有效 PID(进程 ID)。

相关

  1. 我对 如何在 bash 中等待多个子进程完成,并在任何子进程以代码 != 结束时返回退出代码 !=0 的回答0?

I learned from and upvoted @FDS's answer here, because it is good and correct. 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".
  2. The ps --pid "$pid" command returns exit code 0 if the specified PID ("$pid") is running, and some other number if not.
  3. Doing > /dev/null discards all output printed to stdout, since we don't want to see it. Rather, all we want is the exit code ("$?") from the ps --pid "$pid" command to see if that PID is running. More specifically, using > /dev/null redirects stdout output to the /dev/null pseudofile, whose purpose is to discard all incoming input.
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. See the shellcheck output here:

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 e.g. 'if mycmd;', not indirectly with $?.

See the full description for this error code here: https://github.com/koalaman/shellcheck/wiki/SC2181.

So, shellcheck recommends this form instead:

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:

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 "$?", 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)!

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.

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:

// 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. 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:

#!/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.

Related

  1. My answer on How to wait in bash for several subprocesses to finish, and return exit code !=0 when any subprocess ends with code !=0?
囍孤女 2024-09-12 17:01:22

pid

pgrep [pid] >/dev/null

名称

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

-x”表示“完全匹配”。

By pid:

pgrep [pid] >/dev/null

By name:

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

"-x" means "exact match".

染火枫林 2024-09-12 17:01:22

在这里,我将 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

注意:存在竞争条件,因为它不检查该 pid 的调用方式。如果系统重新启动并且 .pid 存在但被不同的应用程序使用,这可能会导致“不可预见的后果”。

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.

#!/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. if the system is rebooted and .pid exists but is used by a different application this might lead 'unforeseen consequences'.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文