Step 1 of 5 · Reading · ~3 min
Read
Production Concerns
Job Control: fg, bg and jobs
After this lesson your shell keeps a table of jobs, so a program can be started in the background, stopped with Ctrl-Z, resumed in either place, listed with jobs, and reported when it finishes. You will reproduce the exact layout of bash's job lines, including the + and - markers that say which job a bare fg or bg would pick.
A job is a command the shell is tracking
When you run sleep 100 &, the shell starts the program without waiting for it and records a job: a small integer id, the process id, the command text and a state. The ids are what the user types after a percent sign (fg %2). The shell prints the id and the pid when it starts a background job:
[1] 5001
A job is in one of three situations. In the foreground it owns the terminal and the shell is waiting for it. Running in the background, it runs while the shell accepts new commands. Stopped, it has been suspended (Ctrl-Z sends SIGTSTP to the foreground job) and waits to be resumed with SIGCONT.
Commands
| Command | Effect |
|---|---|
cmd & | start in the background, print [id] pid |
cmd | start in the foreground and wait |
| Ctrl-Z | stop the foreground job, print its line |
bg [spec] | resume a stopped job in the background, print [id]+ cmd & |
fg [spec] | resume a job in the foreground, print its command |
jobs | list all jobs |
A job spec is %n for job n, %% or %+ for the current job and %- for the previous one. With no spec, fg and bg use the current job.
Current and previous
The job lines carry a marker: + for the current job, the one a bare fg picks; - for the previous one; a space for all others. The current job is the one touched most recently, and "touched" means started, stopped or resumed. So after you stop a job it becomes current, even if a newer background job exists. Keep a list ordered by recent use and read the markers off the last two entries.
The line format
Each line has the shape [id], the marker, two spaces, the state padded with spaces to 23 columns, one more space, and the command. A running background job shows a trailing &; a stopped job does not:
[1]- Stopped vim notes.txt
[2]+ Running make all &
When a background job ends, the shell reports it in the same layout with state Done, or Exit N when the status is not zero. A foreground job that finishes is not reported. A job id is one more than the highest id still in use, or 1 when there are none, so ids are reused after jobs end; pids keep increasing.
Errors
A spec that names no job gives bash: fg: %3: no such job, and a bare fg or bg with nothing to pick gives bash: fg: current: no such job. Resuming a job that is already running in the background gives bash: bg: job N already in background.
Common mistakes
- Giving the
+marker to the newest job instead of the most recently touched one. - Padding the state to the wrong width, or adding the trailing
&to stopped jobs. - Reusing pids when ids are reused.
- Reporting a foreground job's completion.
Your exercise
The starter holds the job table and the helpers that format a line and update recency. You write the command handler. The most likely mistake is not marking a stopped job as the most recently used.
Discussion
Ask a question, share an insight, or help someone who’s stuck.
Sign in to post a comment or reply.
Loading…