In a bash script, what does `kill -0 "$pid"` do, and what does its exit status tell you?
answer
- number zero delivers nothing
- only the existence and permission check
- non-zero merges gone and forbidden
- PIDs get reused; answers go stale
basics
~20 skill -0 sends no signal at all. It performs only the existence and permission check that kill would do first, exiting 0 when a process with that PID exists and you are allowed to signal it, and non-zero otherwise.
solid answer
~50 sSignal number 0 is a special case: the check runs but nothing is delivered, so `kill -0 "$pid"` is a liveness probe rather than an action. Exit status 0 means a process with that PID exists and you have permission to signal it; non-zero means you do not — either it is gone, or it belongs to another user. Bash writes the reason to stderr ("No such process" versus "Operation not permitted"), so scripts normally redirect with `2>/dev/null` and branch on the status. Two caveats matter in practice: PIDs are reused, so a live PID is not proof it is still *your* process, and the answer is stale the instant you get it, so the safer pattern is usually to send the real signal and handle its failure rather than to check first and then act.
code
bash · 12 lines#!/usr/bin/env bash
sleep 5 &
pid=$!
if kill -0 "$pid" 2>/dev/null; then
echo "$pid is alive and I may signal it"
fi
kill -TERM "$pid"
wait "$pid" 2>/dev/null
kill -0 "$pid" 2>/dev/null || echo "$pid is gone"go deeper
Know that kill -0 sends nothing and only reports whether you could signal that PID, and that scripts pair it with 2>/dev/null so the error message stays out of the output.
Explain that non-zero merges two causes — no such process and no permission — that are distinguishable only from stderr, and that a success says nothing about the process being healthy.
Show why check-then-act is a race and why PID reuse makes a bare PID a weak identity. Reach for wait for your own children and for a supervisor when identity really matters.
Own how services are identified and monitored at all: whether raw PIDs are ever an acceptable handle in your tooling, or whether that responsibility belongs to a supervisor with a real notion of process identity.
## What signal 0 means When a process asks the kernel to send a signal, the kernel first checks that the target exists and that the sender is allowed to signal it, then delivers. Signal number 0 stops after the check. Nothing is delivered, the target never notices, and the caller learns only whether the send *would* have been permitted. `kill -0` in bash is that check exposed as a command — it works with the shell builtin as well as `/bin/kill`. ```bash sleep 5 & pid=$! kill -0 "$pid" && echo "alive and signallable" ``` ## Reading the exit status honestly Status 0 answers one specific question: a process with that PID exists *and* you may signal it. Non-zero collapses two different failures into the same value: - the process does not exist — bash prints `kill: (12345) - No such process`; - the process exists but belongs to someone else — bash prints `kill: (1) - Operation not permitted`. Both exit non-zero, so if you care which happened you must read stderr rather than the status. Most scripts do not care and simply want the boolean, so they write `kill -0 "$pid" 2>/dev/null` to keep the message out of their logs. ## What it does not tell you **It is not "is my process running".** PIDs are recycled. A PID recorded ten minutes ago may now belong to something entirely unrelated, and `kill -0` will happily say yes. If identity matters, corroborate it — compare against a command line, or use a supervisor that tracks the process for you rather than a PID you wrote down. **It is not a state check.** A stopped process, or one blocked in the kernel and unresponsive, still passes the check. `kill -0` says the PID is addressable, not that anything behind it is healthy. **It is not durable.** The process can exit one microsecond after the check returns. That makes the check-then-act shape a race: ```bash if kill -0 "$pid" 2>/dev/null; then kill -TERM "$pid" # may already be a different process by now fi ``` The robust form is usually to just do the thing and handle failure: `kill -TERM "$pid" 2>/dev/null || echo "already gone"`. Reach for `kill -0` when you genuinely want to *report* rather than act — a status line, a poll loop, a log message. ## The one place it is genuinely idiomatic Polling for a process you asked to stop. You have sent SIGTERM and want to know when it has actually gone before escalating or before proceeding: ```bash kill -TERM "$pid" 2>/dev/null for _ in $(seq 1 10); do kill -0 "$pid" 2>/dev/null || break sleep 1 done ``` One wrinkle when the target is your own background child: until the shell reaps it, a finished child lingers as a terminated entry that still has a PID, so the poll may keep succeeding briefly. For your own children, `wait` is the right tool — it blocks until the child truly ends and hands you its exit status, which `kill -0` can never give you. ## The shape to remember Use `kill -0` for a cheap, non-destructive "can I address this PID" probe, always with `2>/dev/null`, always treating a yes as advisory rather than as a guarantee, and never as a substitute for `wait` on a process you started yourself.
- Why is checking with `kill -0` before calling `kill -TERM` not actually safe?It is a race. The process can exit between the check and the send, and because PIDs are reused the number may even belong to a different process by then — so the check can be both stale and wrong. Prefer sending the signal and handling the failure: `kill -TERM "$pid" 2>/dev/null || echo already gone`.
- How do you tell "no such process" apart from "not permitted"?Only from stderr. Both exit non-zero, but bash prints `No such process` in the first case and `Operation not permitted` in the second, so a script that must distinguish them has to capture the message instead of branching on the status. Most scripts do not care and just redirect stderr to /dev/null.
- For a background job the script itself started, is `kill -0` the right way to check whether it has finished?No — use `wait`. It blocks until the child truly ends and gives you its exit status, which `kill -0` cannot. A finished child that the shell has not reaped yet still occupies its PID, so the probe can even keep answering yes for a moment after the work is done.
saying these in an interview costs you the question
- Thinks signal 0 is a real signal the process receives
- Reads a non-zero status as proof the process is gone
- Uses it as a health check rather than an addressability check
- Checks with kill -0 then signals, ignoring the race
- Trusts a stale PID from a file without corroborating identity