| | |

LFCA 31 🐧 Killing and Managing Processes

The previous chapter covered viewing processes. This chapter covers acting on them. A process that is stuck, a service that is not responding, a runaway job consuming all the CPU, a background task that should be stopped — all of these are managed with signals. A signal is a small message sent to a process, and the process decides what to do with it. The default behavior for most signals is to terminate, but some signals can be caught and handled, and some cannot. The tools for sending signals are kill, pkill, killall, and the process management commands like jobs, fg, bg, and nohup. This chapter covers what signals are, which ones matter, how to send them, the difference between a graceful shutdown and a forced kill, and the patterns that keep process management safe. It completes the sequence that began with viewing processes and gives the full vocabulary for controlling them.

Key point: A signal is a message sent to a process by the kernel or another process. The common ones are SIGTERM (15), which asks the process to terminate gracefully, and SIGKILL (9), which terminates it immediately and cannot be caught. kill PID sends SIGTERM by default, and kill -9 PID sends SIGKILL. pkill and killall send signals by process name, which is convenient and dangerous. Background jobs started from a shell are managed with jobs, fg, bg, and Ctrl+Z. The nohup command detaches a process from the shell so it survives logout. Only the process’s owner or root can send a signal, and root can send any signal to any process.


What signals are

A signal is an asynchronous notification delivered to a process. It interrupts the process’s normal execution and invokes a handler. The handler may be the default (terminate, ignore, or stop), or a custom function the process installed.

The signal is not a message with content. Unlike a pipe or a socket, a signal carries only its identity. The process knows which signal arrived, and the signal’s meaning is defined by convention and by the handler. The process cannot ask what the sender intended beyond the signal number.

The signal is asynchronous. It can arrive at any point in the process’s execution. The handler runs between instructions, and the process resumes afterward. This is why signal handlers must be careful — they can interrupt a critical section.

The default behavior. Most signals terminate the process. SIGTERM terminates, SIGINT terminates, SIGHUP terminates. SIGSTOP stops the process, and SIGCONT resumes it. SIGKILL and SIGSTOP cannot be caught or ignored.

Why the default is not always desired. A database process that receives SIGTERM should finish its current transaction and flush its buffers before exiting. The default terminate would lose data. So the process installs a handler for SIGTERM that performs the graceful shutdown and then exits. This is what “graceful shutdown” means — the process catches the signal and shuts down cleanly.

Why SIGKILL cannot be caught. The signal is not delivered to the process — the kernel terminates it directly. This is why SIGKILL is the last resort. It cannot be handled, so the process has no chance to clean up, and the resources it held may be left in an inconsistent state.

Why the signal number and the name both matter. kill -9 and kill -KILL are the same. The number is portable across shells, and the name is more readable. Both are accepted, and the convention is to use the name in documentation and the number in quick commands.


The signals that matter

The signal list is long, but a handful appear in everyday work.

SignalNumberDefaultCan catchPurpose
SIGHUP1TerminateYesHangup; often reload config
SIGINT2TerminateYesInterrupt (Ctrl+C)
SIGQUIT3Core dumpYesQuit (Ctrl+)
SIGKILL9TerminateNoForced kill
SIGTERM15TerminateYesGraceful termination
SIGSTOP19StopNoPause the process
SIGCONT18ContinueYesResume the process
SIGUSR110TerminateYesUser-defined
SIGUSR212TerminateYesUser-defined

SIGTERM (15) is the polite request. It asks the process to terminate. A well-written process catches it, shuts down cleanly, and exits. The signal is the default sent by kill, and it is the first signal to try.

SIGKILL (9) is the force. It cannot be caught. The kernel terminates the process immediately. The process has no opportunity to clean up. It is the last resort, used when SIGTERM has not worked.

SIGINT (2) is what Ctrl+C sends. It interrupts the foreground process. A well-written process catches it and exits cleanly. The shell sends it to the process group, so all foreground jobs receive it.

SIGHUP (1) is the reload signal for many services. It was originally the “terminal hung up” signal, but modern daemons often repurpose it as “reload the configuration without restarting.” Sending SIGHUP to nginx or sshd triggers a configuration reload.

SIGSTOP (19) and SIGCONT (18) pause and resume a process. SIGSTOP is like Ctrl+Z but cannot be caught, and SIGCONT resumes. These are useful for temporarily suspending a process to free CPU or memory.

SIGUSR1 (10) and SIGUSR2 (12) are reserved for application-defined purposes. There is no standard meaning; the program’s documentation defines what they do. Some programs use SIGUSR1 to reopen log files after rotation, and SIGUSR2 for other purposes.

Why the distinction between catchable and not. A process that is well-behaved catches SIGTERM and shuts down. A process that is hung ignores it, and SIGKILL is the only option. The distinction is the reason the sequence is “try SIGTERM, wait, then SIGKILL.”

Why sending SIGKILL too early is a mistake. A process that is in the middle of a write to a database or a file that is killed may leave the file or the database in an inconsistent state. The graceful shutdown is what allows the process to finish the write. The SIGKILL is for the case where the process has ignored the graceful request.


The kill command

kill sends a signal to a process identified by PID. The name is misleading — the command sends any signal, not just a kill.

kill 1234              # SIGTERM to PID 1234
kill -15 1234          # same, explicit number
kill -TERM 1234        # same, by name
kill -9 1234           # SIGKILL
kill -KILL 1234        # same, by name
kill -HUP 1234         # SIGHUP, often reload

The default signal is SIGTERM. The -s option is also accepted: kill -s TERM 1234. The different forms are equivalent.

Why kill is not just for killing. The command sends any signal. kill -HUP reloads, kill -STOP pauses, kill -CONT resumes. The name is historical, and the command is the general signal-sending tool.

Sending to multiple processes. kill accepts multiple PIDs.

kill 1234 5678 9101

Each process receives the signal. This is useful when a group of processes should receive the same signal.

The negative PID for process groups. A negative PID sends the signal to the process group rather than a single process.

kill -TERM -1234       # signal the process group 1234

The process group is a set of processes that were started together, often by a shell pipeline or a job. Signaling the group ensures that the whole pipeline receives the signal, not just one process.

Why the process group matters. A shell pipeline like cmd1 | cmd2 | cmd3 creates three processes in one group. Killing the PID of one of them does not kill the others, and the pipeline may hang. Killing the group -PID signals all three.

Why kill fails silently when the process is gone. If the PID does not exist, kill prints “No such process” and exits with a non-zero status. The message is the confirmation that the process has already exited, which is not an error in most cases.

Why kill requires ownership. A non-root user can signal only their own processes. Root can signal any process. The restriction prevents one user from disrupting another user’s work.


pkill and killall

kill requires the PID, which must be found first with ps or pgrep. pkill and killall find the process by name and send the signal in one step.

pkill nginx            # SIGTERM to every process named nginx
pkill -9 nginx         # SIGKILL
pkill -f "node app.js" # match the full command line
pkill -u alice         # processes owned by alice

pkill matches the process name by default, and the -f flag matches the full command line. The -u flag filters by user. The patterns are regular expressions, which means the match is more flexible than an exact name.

killall nginx          # SIGTERM to every process named nginx
killall -9 nginx       # SIGKILL
killall -u alice node  # node processes owned by alice

killall matches the exact name by default, and it has its own set of options. On some systems, killall is a different implementation (the one from psmisc versus the one from SysV), and the behavior differs.

Why name-based signals are convenient. Finding the PID and then sending the signal is two steps. pkill nginx is one. For a service with a known name, the convenience is real.

Why name-based signals are dangerous. A pattern that is too broad matches more processes than intended. pkill node matches every Node.js process, which may include several unrelated applications. pkill -f app matches every process whose command line contains “app,” which could be many. The pattern should be specific, and the -f flag should be used with care.

Why pkill should be tested with pgrep first. The pgrep command uses the same matching rules as pkill, so running pgrep -a pattern first shows what would be matched. This is the safe way to check a pattern before sending a signal.

pgrep -a "node app.js"     # see what would match
pkill -f "node app.js"     # then signal

Why pkill -9 should be the last resort. The name-based form is convenient, and the -9 is tempting. But the graceful SIGTERM should be tried first, and pkill without -9 sends SIGTERM. The -9 is for the case where the graceful signal did not work.

Why a pattern that matches the pkill command itself is a problem. pkill -f pkill matches the pkill command itself, which is a subtle issue. The pgrep and pkill tools exclude themselves from the match, but the shell history and other processes may still match a broad pattern.


Background jobs and job control

A shell can run a process in the background, and the job control commands manage these processes.

Starting a background job. The & at the end of a command runs it in the background.

sleep 1000 &
# [1] 12345

The shell prints the job number and the PID. The prompt returns immediately, and the command runs in the background.

Listing jobs. The jobs command lists the background jobs of the current shell.

jobs
# [1]+  Running    sleep 1000 &

The job number, the state, and the command are shown. The + marks the current job, and the - marks the previous one.

Bringing a job to the foreground. The fg command brings a background job to the foreground.

fg         # bring the current job
fg %1      # bring job 1

The job resumes in the foreground, and the shell waits for it.

Suspending the foreground job. Ctrl+Z suspends the foreground process, returning the prompt.

# press Ctrl+Z
# [1]+  Stopped    some-command

The process is stopped, not terminated. It can be resumed with fg or bg.

Resuming in the background. The bg command resumes a stopped job in the background.

bg         # resume the current job in the background
bg %1      # resume job 1

The job continues running, and the prompt returns.

Why the job control commands are shell-specific. Jobs are tracked by the shell, not by the kernel. A job started in one shell is not visible in another. The jobs command lists only the jobs of the current shell.

Why the job number and the PID are different. The job number is the shell’s label for the job, and the PID is the kernel’s. The job number is used with fg, bg, and kill %1. The PID is used with kill. The % prefix distinguishes the job number from the PID.

Why a background job receives SIGHUP when the shell exits. The shell sends SIGHUP to its background jobs when it exits, which terminates them. This is why a long-running command started with & does not survive logout. The nohup command and disown are the fixes.


nohup and surviving logout

A process started from a shell is a child of the shell, and it receives SIGHUP when the shell exits. To keep a process running after logout, it must be detached from the shell.

nohup. The nohup command runs a program and makes it ignore SIGHUP.

nohup ./long-job.sh &
# nohup: ignoring input and appending output to 'nohup.out'

The command runs in the background, and its output goes to nohup.out in the current directory unless redirected. The process ignores SIGHUP, so it survives the shell’s exit.

Why the output is redirected. A process that is detached from the terminal has no terminal for its standard output. nohup redirects the output to a file, which is why the message appears. The redirection can be overridden: nohup ./job.sh > job.log 2>&1 &.

disown. The disown command removes a job from the shell’s job table, so the shell does not send SIGHUP when it exits.

./long-job.sh &
disown %1

The job continues running, and the shell no longer tracks it. The disown is a shell built-in, so its behavior is shell-specific.

setsid. The setsid command runs a program in a new session, which detaches it from the terminal.

setsid ./job.sh

The process becomes a session leader with no controlling terminal, which is the most complete detachment. This is the mechanism that nohup and disown approximate.

Why the distinction matters. A process that is merely backgrounded with & is still a child of the shell and receives SIGHUP when the shell exits. A process run with nohup ignores SIGHUP. A process run with setsid is in a new session and has no controlling terminal. The three levels of detachment are progressively more complete.

Why systemd is the modern answer. A long-running service should be managed by systemd, not started with nohup. The systemd service has restart policies, logging, and dependency management that the shell cannot provide. The nohup and setsid are for one-off jobs that need to survive a logout, and systemd is for services.

Why the nohup.out file can grow unbounded. The output file is appended to and never rotated. A long-running job that writes to nohup.out can fill the disk. The redirection to a log file with rotation, or the use of systemd with its journal, is the fix.


The graceful shutdown pattern

The correct way to stop a process is to send SIGTERM, wait for it to exit, and send SIGKILL only if it does not. This is the graceful shutdown pattern.

kill 1234              # send SIGTERM
sleep 5                # wait
if kill -0 1234 2>/dev/null; then
  kill -9 1234         # still running, force
fi

The kill -0 sends signal 0, which does nothing but checks whether the process exists. If the process is gone, the check fails silently and the SIGKILL is skipped. If the process is still there, the SIGKILL is sent.

Why the wait matters. A process that receives SIGTERM may take time to shut down — flushing buffers, closing connections, finishing a transaction. The wait gives it the time. Sending SIGKILL immediately after SIGTERM defeats the purpose of the graceful signal.

Why kill -0 is the existence check. Signal 0 is not a real signal; the kernel performs the permission and existence checks but does not deliver anything. It is the standard way to test whether a PID is alive.

Why the pattern is used in scripts. A script that stops a service, a cleanup routine, or a process manager uses the graceful-then-force sequence. The pattern is the correct behavior, and the alternative — kill -9 immediately — risks data corruption.

Why the pattern is not always correct. Some processes genuinely ignore SIGTERM due to a bug, and the SIGKILL is the only option. Some processes have a long shutdown that takes minutes, and the wait should be longer. The timing is a per-process decision, and the pattern is the shape.

Why SIGKILL should never be the first signal. The process may be in the middle of a write, holding a lock, or managing a transaction. The SIGKILL terminates it without cleanup, and the resources may be left inconsistent. The SIGTERM first, and SIGKILL only if necessary, is the discipline.


Complete Example Session

# ============================================
# PART 1: FIND AND KILL A PROCESS
# ============================================

pgrep -a nginx
# 1234 nginx: master process /usr/sbin/nginx
# 1235 nginx: worker process

kill 1234
# SIGTERM sent to the master
# nginx shuts down gracefully

# ============================================
# PART 2: SIGNAL BY NAME
# ============================================

pkill nginx
# SIGTERM to every nginx process

pkill -9 nginx
# SIGKILL (last resort)

# ============================================
# PART 3: SAFE PATTERN CHECK
# ============================================

pgrep -a "node app.js"
# 5678 node app.js

pkill -f "node app.js"
# SIGTERM to the matching process only

# ============================================
# PART 4: RELOAD WITH SIGHUP
# ============================================

kill -HUP 1234
# nginx reloads its configuration

# ============================================
# PART 5: PAUSE AND RESUME
# ============================================

kill -STOP 1234
# process is paused

kill -CONT 1234
# process resumes

# ============================================
# PART 6: BACKGROUND JOB
# ============================================

sleep 1000 &
# [1] 12345

jobs
# [1]+  Running    sleep 1000 &

fg %1
# brings sleep to the foreground

# Ctrl+Z
# [1]+  Stopped    sleep 1000

bg %1
# resumes in the background

kill %1
# terminate the job by job number

# ============================================
# PART 7: NOHUP
# ============================================

nohup ./long-job.sh > job.log 2>&1 &
# [1] 12345
# the process survives logout

# ============================================
# PART 8: GRACEFUL SHUTDOWN
# ============================================

kill 1234
sleep 5
if kill -0 1234 2>/dev/null; then
  kill -9 1234
fi

# ============================================
# PART 9: PROCESS GROUP
# ============================================

ps -eo pid,pgid,cmd | grep nginx
# 1234  1234 nginx: master
# 1235  1234 nginx: worker
# 1236  1234 nginx: worker

kill -TERM -1234
# signals the whole process group

# ============================================
# PART 10: WHEN THE SIGNAL FAILS
# ============================================

kill 1234
# kill: (1234) - Operation not permitted
# You do not own the process, or it is not your UID.

sudo kill 1234
# root can signal any process

# ============================================
# PART 11: WHAT NOT TO DO
# ============================================

# Don't use kill -9 as the first signal
# The process cannot clean up.

# Don't use a broad pkill pattern
# pkill -f app matches everything containing "app".

# Don't kill a process you did not start
# Unless you are root, it fails.

# Don't forget to check with pgrep first
# The pattern may match more than intended.

# Don't kill a process in D state
# It is waiting for I/O and cannot be killed.

# Don't leave nohup.out unbounded
# It grows forever and can fill the disk.

The eleven parts cover the kill command, name-based signals, pattern checking, reload, pause and resume, job control, nohup, graceful shutdown, process groups, permission failures, and the anti-patterns.


Quick Reference

Signals

SignalNumberDefaultCatchPurpose
SIGHUP1TerminateYesReload config
SIGINT2TerminateYesCtrl+C
SIGQUIT3Core dumpYesCtrl+\
SIGKILL9TerminateNoForce kill
SIGTERM15TerminateYesGraceful stop
SIGSTOP19StopNoPause
SIGCONT18ContinueYesResume
SIGUSR110TerminateYesApp-defined
SIGUSR212TerminateYesApp-defined

Signal Commands

CommandPurpose
kill PIDSIGTERM to PID
kill -9 PIDSIGKILL to PID
kill -HUP PIDSIGHUP to PID
kill -0 PIDCheck existence
pkill nameSIGTERM by name
pkill -f patternSIGTERM by command line
killall nameSIGTERM by exact name
kill -TERM -PGIDSignal a process group

Job Control

CommandPurpose
command &Start in background
jobsList jobs
fg %NForeground job N
bg %NBackground job N
Ctrl+ZSuspend foreground
kill %NSignal job N

Detachment

CommandEffect
&Background, still child of shell
nohup cmd &Ignores SIGHUP
disown %NRemove from job table
setsid cmdNew session
systemdFull service management

Graceful Shutdown

StepCommand
1. Send SIGTERMkill PID
2. Waitsleep 5
3. Checkkill -0 PID 2>/dev/null
4. Force if neededkill -9 PID

Best Practices

✅ Do This:

# Find the process first
pgrep -a nginx                                                # ✅

# Try SIGTERM before SIGKILL
kill 1234                                                     # ✅

# Wait, then force if needed
sleep 5 && kill -0 1234 2>/dev/null && kill -9 1234           # ✅

# Check a pattern before signaling
pgrep -a "node app.js" && pkill -f "node app.js"              # ✅

# Use SIGHUP for reload
kill -HUP 1234                                                # ✅

# Use the process group for a pipeline
kill -TERM -1234                                              # ✅

# Use nohup for a job that must survive logout
nohup ./job.sh > job.log 2>&1 &                               # ✅

# Use systemd for services
systemctl restart nginx                                       # ✅

❌ Don’t Do This:

# Don't use kill -9 as the first signal
kill -9 1234  # no graceful shutdown                           # ⚠️

# Don't use a broad pkill pattern
pkill -f app  # matches everything with "app"                  # ⚠️

# Don't kill a process you did not start
kill 1234  # Operation not permitted                           # ⚠️

# Don't kill a process in D state
# It cannot be killed until the I/O completes                  # ⚠️

# Don't forget to check before signaling
# The pattern may match more than intended                     # ⚠️

# Don't leave nohup.out unbounded
# It grows forever                                              # ⚠️

# Don't rely on `&` alone for a job that must survive logout
sleep 1000 &  # receives SIGHUP when the shell exits           # ⚠️

Common Pitfalls

PitfallProblemSolution
kill -9 firstNo cleanupTry SIGTERM first
Broad pkill patternKills unintendedCheck with pgrep
Signal failsNot the ownerUse sudo or your own
Process in D stateCannot be killedWait for I/O
Job lost on logoutSIGHUP terminatesnohup or disown
nohup.out growsDisk fillsRedirect to a log
Pipeline not killedOnly one PID signaledSignal the group
Job number vs PIDWrong target%N for jobs, PID for processes

Real-World Examples

1. Graceful stop

kill 1234

2. Force stop

kill -9 1234

3. Reload config

kill -HUP 1234

4. Signal by name

pkill nginx

5. Signal by command line

pkill -f "node app.js"

6. Check first

pgrep -a "node app.js"

7. Background job

./job.sh &

8. Survive logout

nohup ./job.sh > job.log 2>&1 &

9. Process group

kill -TERM -1234

10. Graceful with fallback

kill 1234 && sleep 5 && kill -0 1234 2>/dev/null && kill -9 1234

Visual: The Signal Flow

┌──────────────────────────────────────────────────────────┐
│  Sender ──► kill ──► kernel ──► signal ──► process       │
│                                              │           │
│                                              ▼           │
│                                     ┌─────────────────┐  │
│                                     │  default handler │  │
│                                     │  OR custom       │  │
│                                     └─────────────────┘  │
│                                              │           │
│                                              ▼           │
│                                     terminate / ignore   │
│                                     / stop / reload      │
│                                                          │
│  SIGKILL bypasses the handler and terminates directly.   │
│                                                          │
└──────────────────────────────────────────────────────────┘

Visual: SIGTERM vs SIGKILL

┌──────────────────────────────────────────────────────────┐
│  SIGTERM (15)                                            │
│                                                          │
│  kill 1234                                               │
│       │                                                  │
│       ▼                                                  │
│  Process receives the signal                             │
│       │                                                  │
│       ▼                                                  │
│  Catches it, shuts down:                                 │
│    - flushes buffers                                     │
│    - closes connections                                  │
│    - finishes transactions                               │
│    - releases locks                                      │
│       │                                                  │
│       ▼                                                  │
│  Exits cleanly                                           │
│                                                          │
├──────────────────────────────────────────────────────────┤
│  SIGKILL (9)                                             │
│                                                          │
│  kill -9 1234                                            │
│       │                                                  │
│       ▼                                                  │
│  Kernel terminates immediately                           │
│       │                                                  │
│       ▼                                                  │
│  No cleanup. Resources may be inconsistent.              │
│                                                          │
└──────────────────────────────────────────────────────────┘

Visual: Graceful Shutdown Pattern

┌──────────────────────────────────────────────────────────┐
│  1. kill PID  (SIGTERM)                                  │
│       │                                                  │
│       ▼                                                  │
│  2. sleep 5   (wait)                                     │
│       │                                                  │
│       ▼                                                  │
│  3. kill -0 PID  (does it still exist?)                  │
│       │                                                  │
│       ├── No  ──► done, the process exited gracefully    │
│       │                                                  │
│       └── Yes ──► 4. kill -9 PID  (force)                │
│                                                          │
│  The wait gives the process time to clean up.            │
│                                                          │
└──────────────────────────────────────────────────────────┘

Visual: Job Control

┌──────────────────────────────────────────────────────────┐
│  $ ./long-job.sh                                         │
│  (foreground, shell waits)                               │
│                                                          │
│  Ctrl+Z                                                  │
│       │                                                  │
│       ▼                                                  │
│  [1]+  Stopped    ./long-job.sh                          │
│  (process paused, prompt returns)                        │
│                                                          │
│  bg %1                                                   │
│       │                                                  │
│       ▼                                                  │
│  [1]+  ./long-job.sh &                                   │
│  (running in the background)                             │
│                                                          │
│  fg %1                                                   │
│       │                                                  │
│       ▼                                                  │
│  (back to the foreground)                                │
│                                                          │
│  kill %1                                                 │
│       │                                                  │
│       ▼                                                  │
│  (terminated by job number)                              │
│                                                          │
└──────────────────────────────────────────────────────────┘

Visual: Detachment Levels

┌──────────────────────────────────────────────────────────┐
│  ./job.sh &                                              │
│    Child of the shell.                                   │
│    Receives SIGHUP on logout.                            │
│                                                          │
├──────────────────────────────────────────────────────────┤
│  nohup ./job.sh &                                        │
│    Ignores SIGHUP.                                       │
│    Survives logout.                                      │
│    Output goes to nohup.out.                             │
│                                                          │
├──────────────────────────────────────────────────────────┤
│  setsid ./job.sh                                         │
│    New session, no controlling terminal.                 │
│    Fully detached.                                       │
│                                                          │
├──────────────────────────────────────────────────────────┤
│  systemd service                                         │
│    Managed by the init system.                           │
│    Restart policy, logging, dependencies.                │
│    The correct tool for a service.                       │
│                                                          │
└──────────────────────────────────────────────────────────┘

Visual: Process Group Signaling

┌──────────────────────────────────────────────────────────┐
│  Shell pipeline:  cmd1 | cmd2 | cmd3                     │
│                                                          │
│  Process group 1234:                                     │
│    1234  cmd1                                            │
│    1235  cmd2                                            │
│    1236  cmd3                                            │
│                                                          │
│  kill 1235                                               │
│    → only cmd2 receives the signal                       │
│    → cmd1 and cmd3 may hang                              │
│                                                          │
│  kill -TERM -1234                                        │
│    → the whole group receives the signal                 │
│    → the pipeline terminates cleanly                     │
│                                                          │
└──────────────────────────────────────────────────────────┘

Summary

ItemValue
SIGTERM15, catchable, graceful
SIGKILL9, not catchable, force
SIGINT2, Ctrl+C
SIGHUP1, reload for daemons
SIGSTOP / SIGCONTPause / resume
killSend signal to PID
pkillSend signal by name
killallSend signal by exact name
jobs / fg / bgJob control
nohupSurvive logout
kill -0Check existence
-PGIDSignal process group

Key takeaways:

  • A signal is an asynchronous notification — the process catches it, ignores it, or is terminated by it, depending on the signal and the handler
  • SIGTERM is the polite request and SIGKILL is the force — the first can be caught and allows cleanup, the second cannot and terminates immediately
  • The graceful shutdown pattern is SIGTERM, wait, then SIGKILL — the wait gives the process time to flush buffers and close connections
  • kill sends any signal, not just a kill — the name is historical, and -HUP, -STOP, and -CONT are all sent with the same command
  • pkill and killall send by name, which is convenient and dangerous — a broad pattern matches more than intended, and pgrep should check the pattern first
  • kill -0 checks whether a process exists — it performs the checks without delivering a signal, and it is the standard existence test
  • Job control is shell-specific — jobs, fg, bg, and Ctrl+Z manage the jobs of the current shell, and the job number is distinct from the PID
  • nohup and setsid detach a process from the shell — a background job with & still receives SIGHUP on logout, and the detachment is what keeps it running
  • The process group is the right target for a pipeline — signaling one PID of a multi-process pipeline leaves the others running, and the negative PID signals the group
  • systemd is the modern answer for services — nohup is for one-off jobs, and a service should be managed by the init system with its restart policies and logging

Remember: Process management is about sending the right signal at the right time. SIGTERM first, wait, then SIGKILL if necessary. Find the process before signaling it, check the pattern before using it, and target the process group when the process is part of a pipeline. The kill command sends any signal, and the graceful shutdown is the discipline that keeps the system consistent.


Stop using slow, ad-bloated tool sites! 🤮

🔎 Search “KandZ Tools” on Google to use many professional utilities for free.

KandZ.me is the ultimate minimalist hub for:
✅ Finance (Mortgage, Interest, Inflation)
✅ Tech (Base64, JSON, Dev Suite, IP)
✅ Health (BMI, BMR, TDEE)
✅ Productivity (Timer, Workspace, QR)

⚡️ Fast & Private
🔒 No data leaves your device
💎 100% Free

🔗 Use it now: https://tools.kandz.me
🔖 Bookmark it—you’ll need it later!