Shell Course 4
Chapter 4: Processes and Tasks
Every program running on your computer exists as one or more processes. When you launch an application, edit a document, or even use the shell itself, you’re creating and interacting with processes. Understanding how to monitor and control these processes gives you tremendous power over your system.
What is a Process?
A process is an instance of a running program. Each process has:
- A unique Process ID (PID)
- A parent process that created it
- Allocated memory and resources
- An owner (the user who started it)
- A state (running, sleeping, stopped, zombie, etc.)
When you run a command in the shell, you’re creating a new process. For example, when you type ls
, the shell creates a process to execute the ls
program, which then terminates when its job is complete.
Process Hierarchy
Processes in Unix-like systems exist in a parent-child hierarchy. Every process (except the very first one, called init
or systemd
on modern systems) has a parent that created it.
This hierarchy begins when your computer boots:
- The kernel starts the
init
process (PID 1) init
spawns system services and your login session- Your login session spawns the shell
- The shell spawns commands you run
Let’s explore the tools that let you see what’s happening under the hood of your system.
The ps
Command
The ps
command (short for “process status”) provides a snapshot of current processes:
1 | $ ps |
This basic output shows:
- PID: Process ID
- TTY: Terminal associated with the process
- TIME: CPU time used
- CMD: Command name
However, the real power comes with options:
1 | $ ps aux |
This comprehensive format shows all processes (not just yours), with detailed information including CPU and memory usage.
- USER: Who owns the process
- PID: Process ID
- %CPU: Percentage of CPU used
- %MEM: Percentage of physical memory used
- VSZ: Virtual memory size
- RSS: Resident set size (non-swapped physical memory)
- TTY: Terminal associated with the process
- STAT: Process state code (R=running, S=sleeping, Z=zombie, etc.)
- START: Start time
- TIME: Cumulative CPU time
- COMMAND: Command with arguments
ps
command is like taking a photograph of your system’s processes at a moment in time. Sometimes useful, but if you want to see processes in motion, you need something more like a film.
Real-time Process Monitoring with top
While ps
gives a static snapshot, top
provides a dynamic, real-time view of processes:
1 | $ top |
This command refreshes every few seconds, showing the most resource-intensive processes at the top. The header provides system-wide information:
- Load averages (system workload)
- Tasks count by state
- CPU usage breakdown
- Memory usage statistics
- Press q to quit
- Press k to kill a process (you’ll be prompted for the PID)
- Press r to renice a process (change its priority)
- Press F to select which columns to display
- Press u to filter by user
A Better Top: htop
If top
is a film, then htop
is that same film but in high definition with a better interface. It may not be installed by default, but it’s worth adding to your toolkit:
1 | # On Debian/Ubuntu |
htop
offers several advantages over top
:
- Color-coded output for better readability
- Visual indicators of CPU and memory usage
- Ability to scroll horizontally and vertically
- Mouse support for interaction
- Built-in kill, nice, and other operations without needing to know PIDs
htop
is like upgrading from a basic digital watch to a modern smartwatch - the core functionality is the same, but the interface and additional features make it much more pleasant to use.
Viewing processes is useful, but controlling them is where the real power lies.
Foreground vs Background Processes
By default, when you run a command in the shell, it runs in the foreground, meaning:
- The shell waits for it to complete before giving you back the prompt
- It receives input from and sends output to your terminal
- You can interrupt it with keyboard shortcuts
But sometimes, you want to run a command and get back to work without waiting for it to finish. That’s where background processes come in.
Running Processes in the Background
To start a command in the background, add an ampersand (&
) at the end:
1 | $ long-running-command & |
The shell returns:
- A job number in brackets
[1]
- The process ID (5243)
The command runs in the background, and you get your prompt back immediately.
1 | $ long-running-command > output.log 2>&1 & |
This redirects both standard output and standard error to output.log
.
Job Control
The shell maintains a list of jobs (commands) that you’ve started. You can view this list with the jobs
command:
1 | $ jobs |
Each job has a number that you can use to refer to it. You can bring a background job to the foreground with fg
:
1 | $ fg %1 |
This brings job 1 to the foreground. You can omit the %
if there’s no ambiguity:
1 | $ fg 1 |
Conversely, you can send a foreground process to the background with Ctrl+Z to suspend it, followed by bg
:
1 | [press Ctrl+Z] |
Terminating Processes
Sometimes, you need to stop a process before it completes naturally. The kill
command sends signals to processes:
1 | $ kill 5243 |
This sends the TERM (terminate) signal to the process with PID 5243, asking it to shut down gracefully.
If a process is stubborn, you can force it to quit:
1 | $ kill -9 5243 |
This sends the KILL signal, which the process cannot ignore.
-9
option should be a last resort. Always try a normal kill
first, as it allows the process to clean up properly.
You can also kill processes by job number in the current shell:
1 | $ kill %1 |
Common Signals
While there are many signals you can send with kill
, the most common are:
- SIGHUP (1): Hangup, often used to make a process reload its configuration
- SIGINT (2): Interrupt, same as pressing Ctrl+C
- SIGTERM (15): Terminate, the default signal sent by
kill
- SIGKILL (9): Kill immediately, cannot be caught or ignored
- SIGSTOP (19): Stop execution, cannot be caught or ignored
To send a specific signal, use the signal number or name:
1 | $ kill -SIGHUP 5243 |
Not all processes are created equal. The system uses a concept called “niceness” to determine how much CPU time to allocate to each process.
Understanding Nice Values
The nice value ranges from -20 (highest priority) to 19 (lowest priority), with 0 being the default. A process with a lower nice value gets more CPU time compared to one with a higher value.
Viewing Process Nice Values
The -l
option to ps
shows the nice value (NI column):
1 | $ ps -l |
Setting Process Priorities
To start a new process with a specific nice value, use the nice
command:
1 | $ nice -n 10 ./large-computation.sh |
This runs large-computation.sh
with a niceness of 10 (lower priority).
To change the priority of a running process, use renice
:
1 | $ renice -n 15 -p 5243 |
This changes the nice value of process 5243 to 15.
Understanding which processes are running is only part of the picture. You also need to know how they’re affecting your system’s resources.
Memory Usage
The free
command shows memory usage:
1 | $ free -h |
The -h
option makes the output human-readable (with units like Gi for gibibytes).
Disk I/O
The iotop
command (which may need to be installed) shows disk read/write activity:
1 | $ sudo iotop |
For a simpler view, you can use iostat
(part of the sysstat package):
1 | $ iostat -x 2 |
This shows extended statistics, refreshing every 2 seconds.
Network Usage
To monitor network traffic, you can use tools like nethogs
or iftop
:
1 | $ sudo nethogs |
These may need to be installed via your package manager.
Overall System Monitoring
For comprehensive system monitoring, you might consider more advanced tools:
glances
: An all-in-one monitoring tool with a user-friendly interfacenmon
: A performance monitor for Linux systemsdstat
: A versatile replacement for various system monitoring tools
As a system administrator or power user, you’ll often need to run commands at specific times rather than manually executing them. Linux and Unix-like systems provide several powerful tools for scheduling tasks.
The at
Command
The at
command allows you to schedule one-time tasks to run at a specific time:
1 | $ at 10:00 PM |
After typing at
with a time specification, you’ll see the at>
prompt. Type each command you want to run, then press Ctrl+D to finish.
1 | $ at 10:00 PM # 10:00 PM today |
at
command is perfect for those “I need to remember to do this later” moments, like a digital version of tying a string around your finger.
Managing Scheduled Jobs
To view pending at
jobs:
1 | $ atq |
To remove a scheduled job:
1 | $ atrm 3 |
The cron
System
While at
handles one-time tasks, cron
is designed for recurring tasks. It works by reading configuration files called “crontabs” that specify when and how often commands should run.
To edit your personal crontab:
1 | $ crontab -e |
This will open an editor where you can add scheduled tasks in the following format:
1 | # minute hour day month weekday command |
This example runs the echo command at 10:00 AM every day.
1 | * * * * * command |
An asterisk (*) means “every” for that position. You can also use:
- Commas for lists:
1,3,5
- Hyphens for ranges:
1-5
- Slashes for steps:
*/10
(every 10th unit)
1 | # Run every hour |
Viewing and Managing Crontabs
To list your current crontab:
1 | $ crontab -l |
To remove your crontab entirely:
1 | $ crontab -r |
In addition to user-specific crontabs, system-wide cron jobs are stored in various locations:
/etc/crontab
: The system crontab file/etc/cron.d/
: Directory for additional crontab files/etc/cron.hourly/
,/etc/cron.daily/
,/etc/cron.weekly/
,/etc/cron.monthly/
: Directories for scripts to run at specific intervals
Sometimes you need to take action when certain conditions are met, like restarting a crashed service or alerting when resources run low.
Basic Monitoring Script
Here’s a simple script to check if a critical process is running and restart it if needed:
1 |
|
Save this as check_apache.sh
, make it executable with chmod +x check_apache.sh
, and run it periodically.
Using watch
for Regular Monitoring
The watch
command runs a command repeatedly, showing the output:
1 | $ watch -n 5 "ps aux | grep mysql" |
This runs ps aux | grep mysql
every 5 seconds, highlighting differences between updates.
Running Commands at System Load Thresholds
The stress
command allows you to run commands when the system load reaches certain levels:
1 | $ sudo apt install stress # Install if needed |
This simulates high CPU, I/O, and memory load for 30 seconds, useful for testing monitoring solutions.
Let’s practice what we’ve learned with some hands-on exercises:
View all your processes:
1
$ ps aux | grep $USER
Start a background process that generates a large file:
1
$ dd if=/dev/zero of=largefile bs=1M count=1000 &
Check its status in the jobs list:
1
$ jobs
Monitor the process and overall system status:
1
$ top -p $(pgrep -d',' -f "dd if=/dev/zero")
Bring the process to the foreground:
1
$ fg %1
Stop it with Ctrl+C.
Start a nice’d process in the background:
1
$ nice -n 15 find / -name "*.log" > logs_found.txt 2>/dev/null &
Check its nice value:
1
$ ps -o pid,comm,nice -p $(pgrep -f "find / -name")
1 |
|
Understanding processes is fundamental to mastering the shell. With the knowledge and tools from this chapter, you can:
- Monitor what’s happening on your system
- Control processes through their lifecycle
- Manage system resources effectively
- Automate routine monitoring tasks
These skills are essential whether you’re managing a personal workstation or administering servers. Process management is the difference between being at the mercy of your computer and being firmly in control of it.
In the next chapter, we’ll explore shell scripts in greater depth, learning how to automate complex sequences of commands and create your own powerful tools.