Job Control — Forground and Background
So far, you’ve been controlling processes by PID and signal. Job control deals with a slightly different situation: the relationship between a command you start from the shell and the terminal that started it.
When you run a command normally, the shell waits for it in the foreground. You can instead put it in the background, move it between foreground and background, or start it so that it can survive after the terminal session ends.
Foreground Jobs
Run a command normally:
sleep 30Your shell is now waiting for sleep to finish.
You cannot enter another shell command in that terminal until it exits:
Shell
│
└── starts sleep
│
│ foreground
▼
terminal is occupiedThis is a foreground job. The shell has given the terminal’s foreground control to that job and waits for it to complete.
Sending A Foreground Job To The Background
You can suspend a running foreground job with:
Ctrl+ZFor example:
sleep 300Press:
Ctrl+ZYou should see something similar to:
[1]+ Stopped sleep 300The process has not exited. It has been stopped. The shell now has your terminal back. You can see the shell’s known jobs with:
jobsFor example:
[1]+ Stopped sleep 300The number in brackets is the job ID assigned by this shell.
This is different from the process’s PID.
Job ID
↓
shell's view of the job
PID
↓
kernel's identifier for the processbg: Continue A Job In The Background
After pressing Ctrl+Z, the job is stopped.
To continue it in the background:
bgYou might see:
[1]+ sleep 300 &Now the shell is free again and the command continues running.
Check:
jobsand you may see:
[1]+ Running sleep 300 &The important transition is:
foreground
↓ Ctrl+Z
stopped
↓ bg
backgroundThe process was not restarted. It was stopped and then continued.
Important (Don’t Skip)
sleep might behave differently as it internally calls linux kernel nanosleep() system call which works regardless of app’s state (running/stopped) but when app is stopped it can’t exit which means it does that only after you unpause it. See nanosleep man page and this Stackoverflow answer for more details.
So, even if you send signal — app should still be designed to catch that. Most applications do but some might not. sleep is just choosen for simplicity. Use larger N seconds (for eg: sleep 300 or even more) so that you can see things happening even though sleep is not behaving internally the same.
Start A Command Directly In The Background
You don’t have to start in the foreground and then move the job.
Add & to the command:
sleep 300 &Note
Be aware that the semicolon after & as such &; is invalid syntax:
&already terminates/backgrounds the command.;is a separate command separator, so&;is invalid syntax.
The shell immediately returns your prompt:
[1] 4821
$Here:
[1]
job ID
4821
PIDThe command is running in the background.
You can verify it with:
jobsor inspect the PID using the process tools you’ve already learned:
ps -p 4821 -o pid,stat,cmdThis demonstrates the relationship between shell job control and normal process management:
Shell
│
├── job ID 1
│
└── PID 4821
│
▼
ProcessThe job ID belongs to the shell’s job-control system. The PID belongs to the Linux process system.
fg: Bring A Background Job Forward
Suppose:
jobsshows:
[1]+ Running sleep 300 &Bring it back to the foreground:
fgThe shell waits for it again.
You can also specify a particular job:
fg %1The % tells the shell that 1 is a job ID rather than a PID.
So:
fg %1means:
Bring job number 1 into the foreground.
jobs, bg, And fg
These commands operate on the shell’s own jobs:
| Command | Purpose |
|---|---|
jobs | Show jobs known to the current shell |
bg | Continue a stopped job in the background |
fg | Bring a job into the foreground |
A useful flow is:
sleep 300
│
│ Ctrl+Z
▼
Stopped
│
│ bg
▼
Background
│
│ fg
▼
ForegroundThis is job control.
What Does Ctrl+C Do?
You’ve probably already used:
Ctrl+Cto stop a command.
This is different from:
Ctrl+ZCtrl+C normally causes the terminal to send SIGINT to the foreground process group.
Ctrl+Z normally causes the terminal to send SIGTSTP, which stops the foreground job.
So:
Ctrl+C
→ interrupt the foreground job
Ctrl+Z
→ stop the foreground jobThe process-control distinction is important.
With Ctrl+C, the usual intention is:
"Stop this command."With Ctrl+Z, the intention is:
"Pause this command; I'll decide what to do with it."After Ctrl+Z, you can use:
bgto continue it in the background or:
fgto bring it back.
What Happens To Terminal Output?
Background processes can still write to the terminal.
For example:
while true; do
echo "background process"
sleep 2
done &The shell gives you your prompt, but the background process can continue printing:
$ background process
background process
background processThis can make the terminal difficult to use. Job control does not mean that a background process becomes completely detached from the terminal. It simply means the shell isn’t waiting for it as the foreground job.
Running command in background (with
&) only detachesstdinso that you can run other commands. Butstdoutandstderrare still attached to the parent shell. This is the reason you keep seeing background process output scattered your terminal. For More see here…
Tip
If you don’t want to see stdout and/or stderr you can just redirect them to a file or to /dev/null. For the above example you can:
while true; do
echo "background process" > output.txt
sleep 2
done &Now output.txt will be scattered with the output, not your terminal till you kill this long running loop or the shell itself.
Standard Input Is Different
A background process that tries to read from the terminal can be stopped because it does not own the terminal’s foreground input.
This is another reason that “background” does not mean “independent of the terminal.”
For simple commands such as:
sleep 300 &This isn’t a problem because sleep doesn’t need input. For interactive programs, foreground/background behavior matters much more. This means you really shouldn’t do read & which doesn’t make sense in most of the cases.
nohup: Survive A Terminal Disconnect
Backgrounding a process does not automatically make it survive when you close the terminal.
For example:
long-running-command &is still associated with the shell and terminal session.
If the shell exits or the terminal connection disappears, the process may receive SIGHUP depending on how it was started and how the shell handles its jobs.
This is where nohup is useful.
nohup long-running-command &nohup means no hangup.
It starts the command in a way intended to protect it from the terminal hangup signal.
For example:
nohup sleep 300 &You can then close the terminal without relying on the shell’s normal interactive job-control behavior to keep the command alive. This means sleep 300 & will still be running in backgroud even if you close your terminal.
Where Does Output Go With nohup?
If you run:
nohup sleep 300 &there is no interesting output to save because sleep doesn’t print anything.
For a command that produces output:
nohup ./backup.sh &nohup normally redirects output that would otherwise go to the terminal to a file named:
nohup.outYou can explicitly choose your own output file instead:
nohup ./backup.sh > backup.log 2>&1 &Now:
stdout → backup.log
stderr → backup.logThis is often more useful for a long-running command because you know exactly where its output is going. For demonstrative purpose:
nohup echo "See Me in myoutput.txt" > myoutput.txt 2>/dev/null & wait; cat myoutput.txtnohup Is Not A Process Manager
It is worth keeping the scope clear. nohup is useful for a command you want to continue after the terminal session goes awayIt is not a replacement for a proper service manager. For example, if you need a program to:
start automatically at boot
restart after failure
maintain logs
run as a specific service accountThat is a different problem.
nohup solves the much smaller problem:
“I started this command interactively, and I don’t want a terminal hangup to stop it.”
disown: Remove A Job From The Shell
Some shells also provide:
disownThis removes a job from the shell’s job table.
For example:
long-running-command &then:
jobsshows the job.
You can remove it from the shell’s job list with:
disown %1After that, the current shell no longer considers it one of its jobs.
A common pattern is:
long-running-command &
disownThis is related to nohup, but they solve different parts of the problem.
nohup
→ protects the command from SIGHUP
disown
→ removes the job from the shell's job tableThey are sometimes used together when you want a command started from an interactive shell to become independent of that shell.
Job ID vs PID
This distinction is worth keeping straight.
Suppose:
sleep 300 &prints:
[1] 4821Then:
1
→ job ID in this shell
4821
→ process ID in LinuxSo these are different:
fg %1uses the shell’s job ID.
Whereas:
kill 4821uses the kernel’s PID.
You can use both systems at the same time:
Shell job control
│
├── %1
│
▼
PID 4821
│
▼
Linux processA Small Practical Workflow
Start a command:
sleep 300Suspend it:
Ctrl+ZCheck it:
jobsContinue it in the background:
bgBring it back:
fgYou can also start directly in the background:
sleep 300 &And for a command that should survive a terminal disconnect:
nohup ./backup.sh > backup.log 2>&1 &These are simple commands, but they cover most of the everyday shell job-control workflow.
What You Should Remember
There are three related but different concepts:
Foreground
→ shell gives the job the terminal and waits for it
Background
→ shell gives you the prompt while the job continues
Detached
→ job is no longer dependent on the interactive shell/terminalThe basic commands are:
Ctrl+Z
→ stop foreground job
bg
→ continue stopped job in background
fg
→ bring background job to foreground
jobs
→ inspect jobs belonging to this shell
nohup
→ protect a command from terminal hangup
disown
→ remove a job from the shell's job tableThe key distinction is that backgrounding is not the same thing as detaching. A command started with & can still be tied to the terminal session, while nohup and disown address different parts of that relationship.