119

I recently came across this in a shell script.

if ! kill -0 $(cat /path/to/file.pid); then
    ... do something ...
fi

What does kill -0 ... do?

slm
  • 369,824

3 Answers3

133

This one is a little hard to glean but if you look in the following 2 man pages you'll see the following notes:

kill(1)

$ man 1 kill
...
If sig is 0, then no signal is sent, but error checking is still performed.
...

kill(2)

$ man 2 kill
...
If sig is 0, then no signal is sent, but error checking is still performed; 
this can be used to check for the existence of a process ID or process 
group ID.
...

So signal 0 will not actually in fact send anything to your process's PID, but will check whether you have permissions to do so.

Where might this be useful?

One obvious place would be if you were trying to determine if you had permissions to send signals to a running process via kill. You could check prior to sending the actual kill signal that you want, by wrapping a check to make sure that kill -0 <PID> was first allowed.

Example

Say a process was being run by root as follows:

$ sudo sleep 2500 &
[1] 15693

Now in another window if we run this command we can confirm that that PID is running.

$ pgrep sleep
15693

Now let's try this command to see if we have access to send that PID signals via kill.

$ if ! kill -0 $(pgrep sleep); then echo "You're weak!"; fi
bash: kill: (15693) - Operation not permitted
You're weak!

So it works, but the output is leaking a message from the kill command that we don't have permissions. Not a big deal, simply catch STDERR and send it to /dev/null.

$ if ! kill -0 $(pgrep sleep) 2>/dev/null; then echo "You're weak!"; fi
You're weak!

Complete example

So then we could do something like this, killer.bash:

#!/bin/bash

PID=$(pgrep sleep) if ! kill -0 $PID 2>/dev/null; then echo "you don't have permissions to kill PID:$PID" exit 1 fi

kill -9 $PID

Now when I run the above as a non-root user:

$ ~/killer.bash 
you don't have permissions to kill PID:15693

$ echo $? 1

However when it's run as root:

$ sudo ~/killer.bash

$ echo $? 0

$ pgrep sleep $

slm
  • 369,824
  • 14
    I would also add this could be used for multi-proc scripts to see if a process is still live. – prateek61 Nov 25 '14 at 18:58
  • 1
    @slm nice find. Using this logic right now in a script i am writing, thanks. – 111--- Nov 25 '14 at 19:01
  • 13
    Prateek61 is right. You can't use pgrep, ps parsing or test -e /proc/$PID in portable scrips, but kill -0 works everywhere. If you're given a PID that may be stale — e.g. a /var/run entry — this is the portable way to check if the process is still alive. – Warren Young Nov 25 '14 at 19:24
  • 1
    In addition to telling you if the PID is alive, it also effectively tells you if it's still running a process from your UID, since you don't have permission to send signals to other UIDs (unless you're root). This makes false positives due to PID reuse less likely. – Barmar Nov 26 '14 at 19:23
  • A failing kill -0 $(pgrep sleep) may not necessarily mean your're weak, it will return false if there's no sleep command running, or if there's more than one and there's one you can't kill, or if one of the sleeps dies in between the pgrep and the kill commands being run. – Stéphane Chazelas Nov 27 '14 at 12:25
  • I'd l like to add that on Debian kill (1) mentions the 0 signal as important but does not explain its meaning (kill (2) is OK in this respect) — a bug was reported against the relevant package (procps) on 13 May 2018 but as today (31 Aug 2019) no action, not even an acknowledgment, was taken by the maintainers. – gboffi Aug 31 '19 at 09:06
38

kill -0 (or its more portable POSIX variant kill -s 0) goes through the motion of sending a signal, but doesn't actually send one. It's a feature of the underlying C API that the shell command exposes in a straightforward way.

kill -s 0 -- "$pid" thus tests whether there is a running process with the given PID (or PGID if $pid is negative), and whether the current process would have the permission to send it (any of the processes in the process group in case of a negative $pid) a signal. It's mostly a way to test whether a process (or process group) is alive.

Keep in mind that even if there is a running process with the expected PID and permissions, this is not necessarily the process that you expect. It's possible that the process that you expect died earlier and its PID was reused for an unrelated process. The right way to monitor processes is by letting their parent do it — a process's PID is not reused until its parent has acknowledged its death (that's why zombies exist), so a process's parent can reliably identify its children by their PID.

4

The kill -0 $pid tells you if a process with $pid exists.

In the snippet

if ! kill -0 $(cat /path/to/file.pid); then
    ... do something ...
fi

the block ... do something ... is executed if a process with the PID that is stored in /path/to/file.pid is running - and - unless the snippet runs as root - if the PID runs under the same user.

The POSIX standard specifies the role of the 0 signal:

If sig is 0 (the null signal), error checking is performed but no signal is actually sent. The null signal can be used to check the validity of pid.

(kill(3p), POSIX.1-2008 - similar wording in POSIX.1-2001)

Note that POSIX specifies both kill -0 and kill -s 0 command line styles (kill(1p)).

In contrast to the kill syscall interface the kill command can't be used to reliably check for the existence of PIDs owned by other users (as a normal user), e.g.:

$ kill -0 123
kill: kill 123 failed: no such process
$ echo $?
1

vs.

$ kill -0 1
kill: kill 1 failed: operation not permitted
$ echo $?
1

When calling the kill syscall one can reliably distinguish these cases via looking at the errno value (cf. e.g. an Python Example).

maxschlepzig
  • 57,532