Bash kill Command – Complete Guide to Terminating Processes

Introduction to kill

The kill command is a fundamental utility in Unix/Linux systems used to terminate or signal processes. Despite its name, kill doesn't just kill processes – it sends various signals to processes, allowing you to control their behavior. Understanding kill is essential for process management, system administration, and troubleshooting.

Basic Syntax

kill [options] <PID>...
kill -l

What kill Does

  • Sends signals to processes
  • Terminates processes gracefully or forcefully
  • Controls process behavior (pause, continue, reload, etc.)
  • Lists available signals

1. Understanding Signals

What are Signals?

Signals are software interrupts sent to processes to notify them of events or request actions. Each signal has a specific meaning and default behavior.

Common Signals

SignalNumberDescriptionDefault Action
SIGHUP1Hangup detectedTerminate
SIGINT2Interrupt (Ctrl+C)Terminate
SIGQUIT3Quit (Ctrl+)Terminate with core dump
SIGKILL9Kill (cannot be caught/ignored)Terminate immediately
SIGTERM15Termination (default kill)Terminate
SIGCONT18Continue if stoppedContinue execution
SIGSTOP19Stop (cannot be caught/ignored)Stop process
SIGTSTP20Terminal stop (Ctrl+Z)Stop process

Listing Available Signals

# List all signals with numbers
kill -l
# List signals with names only
kill -l | tr ' ' '\n' | grep -v '^$'
# List specific signal
kill -l 9
# Output: KILL
# Get signal number from name
kill -l KILL
# Output: 9

2. Basic Usage

Finding Process IDs

# Find PID by process name
pgrep firefox
pidof firefox
# Find PID with ps
ps aux | grep firefox
# Find all PIDs of a process
pgrep -f "python script.py"

Sending Termination Signals

# Send SIGTERM (default, graceful termination)
kill 1234
# Send specific signal by name
kill -SIGTERM 1234
kill -TERM 1234
kill -15 1234
# Send SIGKILL (forceful, immediate termination)
kill -9 1234
kill -SIGKILL 1234
kill -KILL 1234
# Kill multiple processes
kill 1234 5678 9012
# Kill all processes with same name
pkill firefox
killall firefox

Examples

$ ps aux | grep firefox
user     1234  5.2  2.1 2345678 123456 ?      Sl   10:30   0:45 /usr/lib/firefox/firefox
$ kill 1234  # Send SIGTERM
$ kill -9 1234  # Force kill if SIGTERM doesn't work
$ pgrep -f "python server.py"
5678
9012
$ kill -TERM 5678 9012  # Kill multiple

3. Signal Types and Their Uses

SIGTERM (15) - Graceful Termination

# Preferred way to terminate processes
kill -15 1234
kill -TERM 1234
kill 1234  # Default is SIGTERM
# Allows process to:
# - Clean up resources
# - Save state
# - Close files properly
# - Notify child processes

SIGKILL (9) - Forceful Termination

# Last resort when SIGTERM doesn't work
kill -9 1234
kill -KILL 1234
# Process cannot ignore or handle this signal
# No cleanup is performed
# Use only when necessary

SIGHUP (1) - Hangup / Reload

# Reload configuration files (many daemons support this)
kill -1 1234
kill -HUP 1234
# Examples:
kill -HUP $(pgrep nginx)  # Reload nginx configuration
kill -HUP $(pgrep sshd)    # Reload SSH daemon

SIGINT (2) - Interrupt

# Simulate Ctrl+C
kill -2 1234
kill -INT 1234
# Useful for interrupting foreground processes

SIGSTOP (19) and SIGCONT (18)

# Pause a process
kill -STOP 1234
kill -19 1234
# Check if process is stopped
ps aux | grep 1234
# Process will show status 'T' (stopped)
# Resume a stopped process
kill -CONT 1234
kill -18 1234

4. Advanced Usage

Killing Process Trees

# Kill process and all its children
kill -TERM -1234  # Negative PID kills process group
# Using pkill with process groups
pkill -TERM -g 1234
# Find and kill process tree
pstree -p 1234 | grep -oP '\d+' | xargs kill -9
# Kill entire process group
kill -- -$(ps -o pgid= -p 1234 | grep -o '[0-9]*')

Using pkill and pgrep

# pkill - kill processes by name
pkill firefox
pkill -f "python script.py"  # Match full command line
pkill -u username  # Kill all processes of user
pkill -t pts/0  # Kill all processes in terminal
# pgrep - find processes by name
pgrep firefox
pgrep -u username -l  # List with names
pgrep -f "python.*server"  # Regex matching
# Combined example
pkill -TERM -u $(whoami) python

Using killall

# Kill all processes with given name
killall firefox
killall -9 chrome
killall -u username  # Kill all processes of user
# Case-insensitive matching
killall -I FIREFOX
# Wait for processes to die
killall -w firefox  # Wait until all firefox processes are gone
# Interactive confirmation
killall -i firefox  # Ask before killing each process

5. Practical Examples

Script Examples

Process Monitor and Killer:

#!/bin/bash
# proc_killer.sh - Monitor and kill processes by resource usage
KILL_THRESHOLD_CPU=90
KILL_THRESHOLD_MEM=95
CHECK_INTERVAL=10
EXEMPT_PIDS="1 2 3"  # Never kill these PIDs
check_and_kill() {
local pid=$1
local cpu=$2
local mem=$3
local name=$4
for exempt in $EXEMPT_PIDS; do
if [[ $pid -eq $exempt ]]; then
return
fi
done
if (( $(echo "$cpu > $KILL_THRESHOLD_CPU" | bc -l) )); then
echo "Killing process $pid ($name) - CPU usage: $cpu%"
kill -TERM "$pid"
sleep 2
if kill -0 "$pid" 2>/dev/null; then
echo "Process still running, using SIGKILL"
kill -9 "$pid"
fi
elif (( $(echo "$mem > $KILL_THRESHOLD_MEM" | bc -l) )); then
echo "Killing process $pid ($name) - Memory usage: $mem%"
kill -TERM "$pid"
fi
}
while true; do
ps aux | tail -n +2 | while read -r line; do
pid=$(echo "$line" | awk '{print $2}')
cpu=$(echo "$line" | awk '{print $3}')
mem=$(echo "$line" | awk '{print $4}')
name=$(echo "$line" | awk '{for(i=11;i<=NF;i++) printf "%s ", $i}')
check_and_kill "$pid" "$cpu" "$mem" "$name"
done
sleep $CHECK_INTERVAL
done

Graceful Shutdown Script:

#!/bin/bash
# graceful_shutdown.sh - Shut down processes gracefully
SHUTDOWN_TIMEOUT=30
PROCESSES=("nginx" "postgresql" "redis-server")
shutdown_process() {
local proc=$1
local pids=$(pgrep -f "$proc")
if [[ -z "$pids" ]]; then
echo "No $proc processes running"
return
fi
echo "Shutting down $proc (PIDs: $pids)"
# Send SIGTERM to all processes
for pid in $pids; do
kill -TERM "$pid"
done
# Wait for processes to terminate
local waited=0
while [[ $waited -lt $SHUTDOWN_TIMEOUT ]]; do
local remaining=""
for pid in $pids; do
if kill -0 "$pid" 2>/dev/null; then
remaining="$remaining $pid"
fi
done
if [[ -z "$remaining" ]]; then
echo "$proc shutdown successfully"
return 0
fi
sleep 1
((waited++))
done
# Force kill remaining processes
echo "$proc still running after $SHUTDOWN_TIMEOUT seconds, forcing kill"
for pid in $remaining; do
kill -9 "$pid" 2>/dev/null
done
}
# Shut down all processes
for proc in "${PROCESSES[@]}"; do
shutdown_process "$proc"
done
echo "All processes shut down"

Process Tree Killer:

#!/bin/bash
# kill_tree.sh - Kill a process and all its children
kill_tree() {
local parent_pid=$1
local signal=${2:-TERM}
# Get all child PIDs
local children=$(pgrep -P "$parent_pid")
# Recursively kill children first
for child in $children; do
kill_tree "$child" "$signal"
done
# Kill the parent
if kill -0 "$parent_pid" 2>/dev/null; then
echo "Killing $parent_pid with signal $signal"
kill -"$signal" "$parent_pid"
fi
}
# Function to kill process tree with timeout
kill_tree_timeout() {
local parent_pid=$1
local timeout=${2:-10}
# Try graceful termination first
kill_tree "$parent_pid" TERM
# Wait for processes to die
local waited=0
while [[ $waited -lt $timeout ]]; do
if ! kill -0 "$parent_pid" 2>/dev/null; then
echo "Process tree terminated successfully"
return 0
fi
sleep 1
((waited++))
done
# Force kill if still running
echo "Timeout reached, forcing kill"
kill_tree "$parent_pid" KILL
}
# Main script
if [[ $# -lt 1 ]]; then
echo "Usage: $0 <parent_pid> [timeout]"
exit 1
fi
kill_tree_timeout "$1" "${2:-10}"

6. Signal Handling in Scripts

Trapping Signals

#!/bin/bash
# trap_example.sh - Demonstrating signal trapping
cleanup() {
echo "Cleaning up temporary files..."
rm -f /tmp/temp_*
echo "Exiting gracefully"
exit 0
}
handle_interrupt() {
echo "Received interrupt signal (Ctrl+C)"
cleanup
}
handle_terminate() {
echo "Received termination signal"
cleanup
}
handle_hangup() {
echo "Received hangup signal, reloading configuration"
# Reload configuration logic here
}
# Set traps for various signals
trap handle_interrupt SIGINT SIGTERM
trap handle_hangup SIGHUP
trap cleanup EXIT
echo "Process $$ running. PID: $$"
echo "Press Ctrl+C to test interrupt"
echo "Send signals: kill -HUP $$ for reload"
# Simulate work
while true; do
echo "Working..."
sleep 2
done

Checking if Process Exists

# Check if process is running
if kill -0 1234 2>/dev/null; then
echo "Process 1234 is running"
else
echo "Process 1234 is not running"
fi
# Wait for process to end
while kill -0 1234 2>/dev/null; do
echo "Waiting for process 1234 to terminate..."
sleep 1
done
# Function to check process
is_running() {
kill -0 "$1" 2>/dev/null
return $?
}

7. Process Groups and Sessions

Understanding Process Groups

# Show process groups
ps -eo pid,pgid,cmd | head -10
# Kill entire process group
kill -TERM -1234  # Negative PID = process group
# Find process group of a process
ps -o pgid= -p 1234
# Kill all processes in same group as PID
kill -TERM -- -$(ps -o pgid= -p 1234 | tr -d ' ')

Job Control

# Start a background job
long_running_command &
# List jobs
jobs
# Bring job to foreground
fg %1
# Send job to background
bg %1
# Kill job by job number
kill %1
kill -9 %2

8. Security Considerations

Permissions

# Can only kill your own processes (unless root)
kill 1  # Cannot kill init process as normal user
# Output: bash: kill: (1) - Operation not permitted
# Check process ownership
ps -o user= -p 1234
# Root can kill any process
sudo kill -9 1234

Safe Killing Practices

# Always try SIGTERM first
kill -TERM 1234
# Wait a bit
sleep 5
# Check if still running
if kill -0 1234 2>/dev/null; then
echo "Process still running, using SIGKILL"
kill -9 1234
fi
# Never kill critical system processes
# Process 1 (init/systemd) - don't kill!
# Kernel processes (usually in [brackets]) - don't kill!

9. Monitoring and Logging

Logging Killed Processes

#!/bin/bash
# kill_logger.sh - Log all kill commands
LOG_FILE="/var/log/kill_monitor.log"
# Function to log kills
log_kill() {
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
local user=$(whoami)
local pid=$1
local signal=$2
local process_info=$(ps -p "$pid" -o comm= 2>/dev/null)
echo "$timestamp - User: $user - PID: $pid - Signal: $signal - Process: $process_info" >> "$LOG_FILE"
}
# Override kill command
kill() {
local pid=$1
local signal=${2:-TERM}
# Log the kill attempt
log_kill "$pid" "$signal"
# Execute real kill
command kill "$@"
}
# Example usage
kill 1234
kill -9 5678

Audit Trail

# Check audit logs for kill commands
sudo ausearch -m task -c kill
# Check process history
lastcomm | grep kill
# Monitor kill commands with auditd
sudo auditctl -a exit,always -S kill

10. Troubleshooting

Common Issues

# Process won't die
kill -9 1234  # Still running?
# Check if process is zombie
ps aux | grep 1234
# Zombie shows as 'Z' in STAT column
# Permission denied
kill 1234  # Error: Operation not permitted
# Check ownership and try with sudo
# No such process
kill 1234  # Error: No such process
# Process already terminated
# Signal number out of range
kill -100 1234  # Error: Invalid signal
# Check valid signals with kill -l

Debugging

# Trace system calls for kill
strace -e kill kill 1234
# Check signal handling of process
cat /proc/1234/status | grep -i sig
# See pending signals
ps -o pending= -p 1234
# Monitor signals to process
kill -CONT 1234

11. Integration with Other Commands

Using with ps

# Kill processes by pattern
ps aux | grep python | awk '{print $2}' | xargs kill -9
# Kill processes older than certain time
ps -eo pid,etime,cmd | grep "python" | awk '$2 ~ /[0-9]+-[0-9]+:[0-9]+/ {print $1}' | xargs kill
# Kill processes with specific state
ps -eo pid,stat,cmd | grep "^ *[0-9]\+ Z" | awk '{print $1}' | xargs kill -9  # Kill zombies

Using with find

# Kill processes using specific files
lsof /path/to/file | tail -n +2 | awk '{print $2}' | xargs kill -9
# Kill processes in specific directory
find /proc -maxdepth 1 -type d -name "[0-9]*" 2>/dev/null | \
while read proc; do
if readlink "$proc/cwd" | grep -q "/target/dir"; then
kill -9 $(basename "$proc")
fi
done

Using with systemctl (systemd)

# For system services, use systemctl instead of kill
sudo systemctl stop nginx
sudo systemctl kill nginx  # Sends SIGKILL to all processes of service
sudo systemctl kill -s HUP nginx  # Send specific signal

12. Signal Table Reference

Complete Signal List

#NameDescriptionDefault Action
1SIGHUPHangup detectedTerminate
2SIGINTInterrupt from keyboardTerminate
3SIGQUITQuit from keyboardCore dump
4SIGILLIllegal instructionCore dump
5SIGTRAPTrace/breakpoint trapCore dump
6SIGABRTAbort signalCore dump
7SIGBUSBus errorCore dump
8SIGFPEFloating point exceptionCore dump
9SIGKILLKill signalTerminate
10SIGUSR1User-defined signal 1Terminate
11SIGSEGVInvalid memory referenceCore dump
12SIGUSR2User-defined signal 2Terminate
13SIGPIPEBroken pipeTerminate
14SIGALRMTimer signalTerminate
15SIGTERMTermination signalTerminate
16SIGSTKFLTStack faultTerminate
17SIGCHLDChild stopped or terminatedIgnore
18SIGCONTContinue if stoppedContinue
19SIGSTOPStop processStop
20SIGTSTPStop typed at terminalStop
21SIGTTINTerminal input for backgroundStop
22SIGTTOUTerminal output for backgroundStop
23SIGURGUrgent condition on socketIgnore
24SIGXCPUCPU time limit exceededCore dump
25SIGXFSZFile size limit exceededCore dump
26SIGVTALRMVirtual alarm clockTerminate
27SIGPROFProfiling timer expiredTerminate
28SIGWINCHWindow resize signalIgnore
29SIGIOI/O now possibleTerminate
30SIGPWRPower failureTerminate
31SIGSYSBad system callCore dump

13. Best Practices

Kill Command Best Practices

  1. Always try SIGTERM first:
kill -TERM 1234
sleep 5
kill -0 1234 2>/dev/null && kill -9 1234
  1. Check process ownership:
if [[ $(ps -o user= -p 1234) == "$USER" ]]; then
kill 1234
else
sudo kill 1234
fi
  1. Verify process exists:
if kill -0 1234 2>/dev/null; then
kill -TERM 1234
else
echo "Process 1234 not running"
fi
  1. Use process groups for related processes:
kill -TERM -1234  # Kill entire process group
  1. Log important kills:
logger "Killing process 1234 (high CPU usage)"
kill -9 1234

Safety Checklist

  • [ ] Is this my process or do I have permission?
  • [ ] Is this a critical system process?
  • [ ] Have I tried SIGTERM before SIGKILL?
  • [ ] Are there dependent services that might be affected?
  • [ ] Have I saved all important data?
  • [ ] Do I have the correct PID?
  • [ ] Is there a more graceful shutdown method available?

14. Quick Reference Card

Common Kill Commands

CommandDescription
kill 1234Send SIGTERM to PID 1234
kill -9 1234Send SIGKILL to PID 1234
kill -TERM 1234Send SIGTERM by name
kill -SIGKILL 1234Send SIGKILL by full name
kill -lList all signals
kill -l 9Get name of signal 9
killall firefoxKill all firefox processes
pkill -f "python script"Kill processes matching pattern
pgrep firefoxFind firefox PIDs
kill -STOP 1234Suspend process
kill -CONT 1234Resume process
kill -HUP 1234Hangup/reload process

Signal Quick Reference

SignalNumberUse Case
SIGTERM15Graceful termination (default)
SIGKILL9Forceful termination (last resort)
SIGHUP1Reload configuration
SIGINT2Interrupt (Ctrl+C)
SIGSTOP19Suspend process
SIGCONT18Resume suspended process
SIGUSR110User-defined action
SIGUSR212User-defined action

Exit Codes

CodeMeaning
0Success
1Failure (unspecified)
2Invalid option
64Invalid signal specification
65Process not found

Conclusion

The kill command is essential for process management in Unix/Linux systems:

Key Points Summary

  1. Signals: kill sends signals, not just termination requests
  2. Default Signal: SIGTERM (15) - graceful termination
  3. Force Kill: SIGKILL (9) - immediate termination (last resort)
  4. Process Groups: Use negative PIDs to kill process groups
  5. Permissions: Can only kill your own processes (except root)
  6. Signal Handling: Processes can trap and handle many signals
  7. Multiple Tools: kill, pkill, killall for different use cases

Best Practices

  1. Always try SIGTERM first - Allow processes to clean up
  2. Use SIGKILL only when necessary - It doesn't allow cleanup
  3. Verify PIDs - Ensure you're killing the right process
  4. Check permissions - Use sudo when needed
  5. Consider dependencies - Killing one process may affect others
  6. Log important kills - For audit and troubleshooting
  7. Use process groups - For related processes

Quick Reference

SituationCommand
Normal terminationkill 1234
Force terminationkill -9 1234
Reload configkill -HUP 1234
Suspend processkill -STOP 1234
Resume processkill -CONT 1234
Kill by namepkill firefox
Kill all with namekillall firefox
List signalskill -l
Check if runningkill -0 1234

The kill command's versatility in sending different signals makes it an indispensable tool for process control, from graceful shutdowns to forceful terminations and everything in between.

Leave a Reply

Your email address will not be published. Required fields are marked *


Macro Nepal Helper