Learn › Linux Foundations › Job Control
jobs - a hands-on Linux lab on a real virtual machine.
Read the roster of every program you backgrounded or paused in this shell with jobs. The four-part line (number, + / - symbol, state, command), -l for real PIDs, -r / -s / -p to filter, and what Done and an empty list mean. jobs is per-shell and PIDs vary, so the drills teach the roster shape and the marks.
You sent a command to the background with &, and your prompt came straight back so you could keep working. Good. But now that program is running somewhere you cannot see it. It has no window. It is not scrolling text at you. So how do you get it back? How do you even know it is still alive?
You need a roster: a list of every program you started from this terminal that is still running or paused, each with a number you can call it back by. There is one command that prints exactly that roster, and it is called jobs.
The black boxes in this lesson are a practice terminal: a safe sandbox that only checks the one command each step teaches, so you cannot break anything. The job numbers you see ([1], [2]) are stable, but the raw process ID numbers are assigned fresh every time a program launches, so those will read differently for you. Each output here is one honest capture, kept as an example.
A job is a command you started from this shell that the shell is keeping track of: a background command you launched with &, or a command you paused. jobs prints the list of them. Each one gets a job number in square brackets, like [1] or [2], and a state telling you whether it is running or stopped.
Think of it like a coat check. When you hand over a program to the background, the shell gives you a numbered ticket. jobs is you reading the wall of tickets: which coats are still hanging, and what number to say to get one back.
One thing to fix in your mind now, because it surprises almost everyone later: this roster belongs to ONE shell. jobs only knows about the programs started from the exact terminal you type it in. Open a second terminal and its jobs list starts empty, no matter what is running next door.
To have something to list, imagine you have already sent two harmless waiting commands to the background. sleep 100 & and sleep 200 & each just sit quietly for a number of seconds and do nothing else, which makes them perfect practice jobs. With two of them parked in the background, ask the shell to show you the roster:
jobs
prompt: student@linuxcamp:~$ answer: jobs output: [1]- Running sleep 100 & [2]+ Running sleep 200 & hint: Just the one word and Enter, no flags: jobs
Two jobs, two lines. Read one line left to right. [1] is the job number, the ticket you would use to call it back. Next to it is a symbol, - or +, which you will decode in a moment. Then Running, the state: this job is alive and working. Finally sleep 100 &, the exact command you started, printed back so you know what job [1] actually is. The second line is the same shape for job [2]. That four-part line (number, symbol, state, command) is every jobs line you will ever read.
Those little + and - marks are not decoration. They tell you which job the shell will act on if you do not name one.
The + marks the current job: the default. Plain commands like bare fg (bring to foreground) or bare bg (resume in background) will grab this one if you do not give them a number. The - marks the previous job: the one that becomes current next, the moment the + job finishes. Every other job has no symbol at all.
So in the roster you just read, [2]+ is the current job and [1]- is next in line. Look again with that in mind:
There is only ever one + and, if you have two or more jobs, one -. The newest job you background or stop takes the + spot, and the one that had it drops to -. So the current job is usually just the last one you touched.
The job number [1] is the shell's own private ticket. But every running program also has a process ID, or PID, a number the whole system uses to identify it. Job numbers are small and local to your shell; PIDs are large and known system-wide. Sometimes you need the PID, for example to hand it to another tool later.
The -l flag, short for long, prints the same roster with the PID added in. Ask for the long form:
jobs -l
prompt: student@linuxcamp:~$ answer: jobs -l output: [1]- 12345 Running sleep 100 & [2]+ 12346 Running sleep 200 & hint: Add the -l flag for the long form: jobs -l
The PIDs shown here, 12345 and 12346, belong to this one capture. On YOUR machine those numbers will be completely different, and they change again every single time you launch a program. That is expected: the system hands out a fresh PID to every process as it starts. The job number [1] is yours to rely on; the PID is not. What stays the same everywhere is the SHAPE: -l slots the PID in right after the job number.
When you have many jobs, you often want only part of the list. Three flags narrow it down.
-r shows only the running jobs. -s shows only the stopped ones (a job you paused). -p prints only the PIDs, one per line, with nothing else, which is handy when you want to feed those numbers straight to another command.
Ask for only the PIDs to feel the narrowest form:
jobs -p
prompt: student@linuxcamp:~$ answer: jobs -p output: 12345 12346 hint: Add the -p flag to print PIDs only: jobs -p
Again, those two numbers are this capture's PIDs and yours will differ. -p strips everything but the PID: no job number, no state, no command, just the bare process IDs, one per line. That plain list is exactly the shape other tools want to read, which is the whole reason -p exists.
Jobs do not live forever. When a background job finishes on its own, the shell tells you once. The next time you check the roster, jobs reports it as Done, and after that it is gone for good, dropped off the list. So if job [1], your sleep 100 &, reaches the end of its wait, a later jobs shows this:
prompt: student@linuxcamp:~$ answer: jobs output: [1]- Done sleep 100 [2]+ Running sleep 200 & hint: The same jobs command shows a finished job as Done: jobs
That Done line is a farewell, not a status you can act on. The shell is telling you job [1] completed, and this is the last time you will see it. Run jobs once more and [1] is gone entirely, leaving only [2]. This is also why a brand-new terminal, or a shell where every job has finished, prints NOTHING at all when you run jobs. No error, no message, just your prompt again, because there is simply no roster to show.
Scaffolding off. No command is printed this time. You have every piece you need.
You have a couple of jobs parked in the background, and you want the full roster. But you also need the real system process ID of each one, not just the shell's [1] and [2] ticket numbers. Ask for the roster in its long form.
prompt: student@linuxcamp:~$ answer: jobs -l output: [1]- 12345 Running sleep 100 & [2]+ 12346 Running sleep 200 & hint: Recall the flag that stands for long, the one that adds the PID. Think jobs, then -l.
The flag is -l, for long. It gave you the whole roster with each job's PID slotted in after its number. Your own PIDs will read differently, and will differ again on the next run, but the shape, job number then PID then state then command, is what you will see on any machine. You recalled a flag from its meaning alone, which is exactly the recall the real machine will ask of you.
You earned this cheat sheet. Every row is a form of jobs you just ran:
And the marks you can now read: + is the current job (what bare fg and bg grab), - is the previous job, Running and Stopped are the live states, and Done is a finished job saying goodbye one last time.
Remember the per-shell rule above all. jobs is a roster for the ONE terminal you type it in. If you background a command in one window and its jobs list looks empty in another, nothing is broken: you are just reading a different coat check.
The practice terminal has shown you the shape of jobs: the four-part roster line, the + and - marks for current and previous, -l for real PIDs, -r, -s, and -p to filter the list, and what Done and an empty roster mean. Every one of those you typed yourself, and one you recalled from its meaning alone.
The Job Control module ends with one real Linux machine, the Job Control capstone mission, and that is where you run jobs for real, against programs you actually background and pause yourself. A VM boots just for you. It hands you objectives that use exactly what you practiced across this module: sending work to the background, pausing it, resuming it, and reading the roster of it all. One difference from here: the mission shows no commands. You read the objective, you recall the command, you type it. That recall is what makes it stick.
Finish the other Job Control lessons, then go read a real roster of your own running jobs.
Practice jobs in a real Linux terminal at The Linux Camp. Progress is verified automatically as you type commands on the machine.