Getting Started with Job Control - jobs, fg, bg, and Ctrl+Z

Getting Started with Job Control - jobs, fg, bg, and Ctrl+Z

What you'll be able to do

  • Pause a running command with `Ctrl+Z` and get your terminal back
  • Move work between foreground and background with `fg` and `bg`
  • Tell several jobs apart with `jobs` and target one with `%n`

Prerequisites (read these first)

What You'll Learn

Target Audience: Anyone who's been editing a file in vim or running a long command and wanted to "just check one thing" in the same terminal — and accidentally killed everything with Ctrl+C.

Introduction: The Day Lina Killed Her Vim Session

Lina: Senpai, listen! I was editing a long config file in vim, and I needed to run ls in another terminal. I didn't know how to open a new one, so I just hit Ctrl+C — and it killed the whole vim session. I lost every unsaved change.
Linny-senpai: Ouch. The key combo you actually wanted exists, though. It's Ctrl+Z (Control-Z).
Lina: Z, not C?
Linny-senpai: Right. Ctrl+C kills the running command. Ctrl+Z only pauses it and sets it aside.
Linny-senpai: Pausing hands your terminal back, so you can run other commands. When you are done, fg returns you to the paused work.
Lina: That sounds like magic! So I could have kept vim alive after all.
Linny-senpai: It's called "job control" — a basic feature every POSIX shell (bash, zsh) provides. Today you only need four things: Ctrl+Z (pause), bg (resume in background), fg (return to foreground), jobs (list).

The Practical Pattern

  • Want your terminal back? → Ctrl+Zbg (keeps running in the background)
  • Want to pause and leave it alone? → Ctrl+Z by itself (stays paused)
  • Want to come back to it? → fg
  • Forgot what's running? → jobs

Learn the escape route first: when the screen looks frozen

Job control has moments where the screen seems stuck. Work down this table and you will always get out.

What you see How to get out
Command still running, no promptA symbol (like $ or #) shown when the shell is waiting for your input. Press Ctrl+Z to pause it — the prompt comes back
Just pressed Ctrl+Z, unsure what's next fg returns it to the front, bg sends it behind. Both are reversible
Not sure what is paused Run jobs to list everything, then pick one with fg %1
You really want it gone Check the number with jobs, then kill %1 (never drop the %)

Ctrl+Z is not a kill. Pressing it never discards your work, so try it without fear.

What a terminal is

A terminal is the window where you type text and get text back. "Terminal" and "console" are two names for much the same thing.

In this article, "your terminal comes back" means "the $ prompt returns and you can type the next command." That $ symbol is called the prompt.

Assumed Environment

  • bash / zsh (job control is a standard POSIX shell feature; dash also has jobs / fg / bg)
  • Off by default in non-interactive shells (sh -c '...' and inside shell scripts)
  • All keystroke examples assume an interactive terminal session

1. "Job" vs. "Process" — What's the Difference?

Conclusion: A process is an OS-level program; a job is one shell command, referenced by %n.

Lina: What exactly is a "job"? Is it different from a "process"?
Linny-senpai: Same thing, different lens. A process is what the OS sees: each running program. A job is what your shell sees: one command you typed, as a single unit.
Lina: So a job is shell-side, a process is OS-side?
Linny-senpai: Exactly. If you type ls | grep .txt | sort, the OS creates three processes, but the shell treats it as one job. When you hit Ctrl+Z, the shell pauses the whole job — all three processes — at once.

Foreground and background

  • Foreground: the side that receives your keystrokes. While it runs, your terminal does not come back
  • Background: the side that runs out of sight. Your terminal stays free for you

Think of a checkout line. The foreground job is the person standing at the register. A background job is the person holding a ticket and waiting somewhere else.

Job Number vs. PID

Type Example Assigned by Used for
Job number %1 The shell fg %1, kill %1, etc.
PID 12345 The kernelThe core program of an OS. It bridges hardware and software. kill 12345, ps output

Memory trick: Job numbers always take a leading %. It's fg %1 (not fg 1), kill %1 (not kill 1).

kill 1 does not mean "job 1" — it targets the process with PID 1, which is systemd, the parent of the whole system. A regular user gets "Operation not permitted." Either way, the job you wanted to stop keeps running.

2. Ctrl+Z: Pause Right Now

Conclusion: Ctrl+Z pauses a running job without killing it, handing your terminal back.

Linny-senpai: This is the single most important keystroke. Open vim, tail -f, python interactive — anything that holds your terminal — then press Ctrl+Z.
Lina: Won't it freeze? Can I really bring it back?
Linny-senpai: You can. "Paused" is not "killed." Think of it as putting the program in the freezer. fg thaws it out and resumes as if nothing happened.

Try It

$ sleep 100

sleep 100 does nothing for 100 seconds. Your terminal is locked the whole time.

Now press Ctrl+Z.

^Z
[1]+  Stopped                 sleep 100
$

If you see [1]+ Stopped, it worked. Notice the $ prompt is back — the terminal is yours again.

Reading [1]+

  • [1] = job number 1
  • + = the most recently touched job (the default target for fg / bg)
  • Stopped = paused (consuming no CPU)

You Can Now Run Other Commands

$ ls
$ pwd
$ echo "free to do other things"

sleep stays frozen in the background while you do whatever you want. That's the magic of Ctrl+Z.

3. fg: Bring Back / bg: Resume Behind

Conclusion: fg brings a stopped job to the front; bg resumes it in the background.

Lina: How do I un-pause a stopped job?
Linny-senpai: Two choices. fg (short for foreground) brings it back to the front and resumes it. bg (short for background) resumes it out of sight.
Lina: How do I pick between them?
Linny-senpai: Use fg when you want to face the job again. Use bg when you want to keep working on something else.

fg: Back to Foreground

Let's bring back the sleep 100 from before.

$ fg
sleep 100

sleep continues from where it left off, and the terminal is locked again. Wait it out, hit Ctrl+Z again, or Ctrl+C to kill it.

bg: Resume in Background

If you want it running but don't want to wait for it:

$ sleep 100
^Z
[1]+  Stopped                 sleep 100
$ bg
[1]+ sleep 100 &
$

It moves from Stopped to & (running in background). sleep keeps ticking while you do other things.

Not all commands work with bg: Interactive full-screen apps like vim can't "wait for input in the background," so bg-ing them just sends them back to a stopped state (Stopped (tty input)). For vim, the right rhythm is Ctrl+Z to pause → fg to return — don't try to bg it.

4. Append &: Background From the Start

Conclusion: Append & to run in the background from the start; redirect output to a file.

Linny-senpai: If you know up front "this needs to run in the background," append & when you launch it.
Lina: So instead of Ctrl+Z → bg in two steps, do it in one?
Linny-senpai: Right, same end result. Ctrl+Z → bg is "I started it and changed my mind," & is "send it to the back from the start."

Using &

$ sleep 100 &
[1] 12345
$

[1] is the job number, 12345 is the PID. Prompt returns immediately.

$ jobs
[1]+  Running                 sleep 100 &

Status is Running, not Stopped.

Real Example: Background Log Collection

$ tail -f /var/log/syslog > mylog.txt &
[1] 23456
$ # do other things while it runs
$ vim config.txt

Run tail -f in the background while editing a file with vim. Classic parallel workflow.

With & alone, output bleeds into your terminal: Standard output (a command's ordinary results) still prints to your terminal by default, and so does standard error (its error messages). If it's noisy, redirect with > file 2>&1 to send output to a file (or > /dev/null 2>&1 to discard).

5. jobs: See What's Running

Conclusion: jobs lists every job the shell manages; target one with %n, always with a %.

Lina: With multiple jobs running, I'll lose track of what's where.
Linny-senpai: One command fixes that: jobs. Lists every job your current shell is managing.

Basic Usage: jobs

$ sleep 100 &
[1] 12345
$ sleep 200 &
[2] 12346
$ vim notes.txt
# Ctrl+Z to pause
$ jobs
[1]   Running                 sleep 100 &
[2]-  Running                 sleep 200 &
[3]+  Stopped                 vim notes.txt

Three jobs visible.

  • + = most recent (default fg / bg target — vim here)
  • - = previous one (sleep 200)

Target a Specific Job: %n

$ fg %1     # bring sleep 100 to the front
$ bg %3     # send vim to background (it stays paused)
$ kill %2   # terminate sleep 200

Check before you kill

Unlike closing a window in a GUI, kill never asks whether you want to save. Anything unsaved in an editor is simply gone.

  • Run jobs first and confirm you picked the right job
  • For an editor or any job with work in progress, use fg to return to it and save properly instead of killing it
  • Practice on sleep. It holds nothing you could lose, so you can try freely

Don't forget the %

kill 1 targets PID 1 (systemd), not job 1. A regular user is blocked by permissions. Even as rootThe special administrator account allowed to do anything on the system. it only makes systemd re-read its configuration — the job you aimed at is untouched. Make % muscle memory whenever you reference jobs.

Useful jobs Options

Option Effect
jobs -l Also show PIDs
jobs -p PIDs only (handy for scripting)
jobs -r Only running jobs
jobs -s Only stopped jobs

6. What Happens When You Close the Terminal?

Conclusion: By default SIGHUP kills jobs on exit; use nohup, disown, or tmux to survive.

Lina: If I left background jobs running and closed the terminal, what happens?
Linny-senpai: They usually die. When you close the terminal window or the SSH connection drops, the shell receives SIGHUP (hangup), and it passes that on to its child jobs.
Lina: What is a signal?
Linny-senpai: A signal is a short message sent to a process. It carries something like "please finish" or "stop right now," identified by a name and a number.
Lina: So a long job I left in the background can just disappear when I close the terminal?
Linny-senpai: Yes. That's what nohup and disown are for. And for the most robust solution, tmux.

nohup: Ignore SIGHUP From the Start

$ nohup ./long_script.sh > output.log 2>&1 &
[1] 34567

Prefix with nohup and the job ignores SIGHUP when the shell exits. Log out and it keeps running.

disown: Detach From Shell After Launch

$ ./long_script.sh &
[1] 45678
$ disown %1
$ exit   # closing the terminal window won't kill %1

If you started a job with & and then realized you want it to survive logout, disown is your tool.

tmux is more bulletproof

nohup / disown only keep the job alive past disconnect — but you lose the screen output. With tmux the whole session is saved on the server, and you can later tmux attach to come back to the live output. For long jobs where you want to see what happened, tmux wins. → Getting Started with tmux

7. Common Pitfalls

Conclusion: The classic traps: Ctrl+C vs Ctrl+Z, kill 1, stray output, and bg-ing vim.

Lina: Senpai, what mistakes do beginners typically make?
Linny-senpai: Four. These cover most of the first-month landmines.

Pitfall 1: Mixing Up Ctrl+C and Ctrl+Z

Symptom: You meant to pause but the job died.

Cause: Confusing Ctrl+C (SIGINT — terminates) with Ctrl+Z (SIGTSTP — pauses).

Fix: Remember "C = Cancel, Z = Zzz (sleep)." Ctrl+Z is non-destructive — your vim work is safe.

Pitfall 2: Typing kill 1 Instead of kill %1

Symptom: kill 1 says "Operation not permitted," and the job you wanted to stop is still running.

Cause: You confused job number with PID and forgot the %. kill 1 sends a signal to PID 1 (systemd).

Fix: Always prefix job references with %. When in doubt, run jobs -l first to see the PID — or use kill %% to target the most recent job.

Pitfall 3: Background Output Crashing Your Prompt

Symptom: Output from a backgrounded command splatters into the middle of whatever you're typing.

Cause: Stdout and stderr still go to the terminal in the background.

Fix: Redirect with > file 2>&1 & (to a log file) or > /dev/null 2>&1 & (to discard).

Pitfall 4: vim Won't Run After bg

Symptom: You did Ctrl+Z then bg on vim, but jobs shows Stopped (tty input) forever.

Cause: vim needs to read from the terminal. In the background it can't, so the shell auto-pauses it.

Fix: For interactive full-screen apps (vim, top, nano, etc.), stick to Ctrl+Z to pause → fg to resume. Never bg them.

8. Templates: Job Control Without Accidents

Conclusion: vim bounces via Ctrl+Z and fg; long jobs use &; survive logout with tmux.

Copy-paste: Run a command while editing in vim

# 1. Editing in vim
$ vim config.txt
# Ctrl+Z to pause

# 2. Terminal is back — do other things
$ ls /etc/
$ grep "error" /var/log/syslog

# 3. Resume vim
$ fg

The point is to bounce back and forth without closing vim. Build the rhythm: Ctrl+Z → side task → fg.

Copy-paste: Run a long job in the background

# Send output to a file so it doesn't trash your terminal
$ ./long_script.sh > output.log 2>&1 &
[1] 12345

# Check progress
$ jobs
$ tail -f output.log

# Terminate if needed
$ kill %1

Forgetting > output.log 2>&1 is the most common mistake. Keep them paired.

Copy-paste: Survive logout

# nohup from launch
$ nohup ./long_script.sh > output.log 2>&1 &
[1] 12345

# Or disown after the fact
$ ./long_script.sh > output.log 2>&1 &
[1] 12345
$ disown %1

# The most robust approach — tmux preserves the whole screen (recommended)
$ tmux
$ ./long_script.sh
# Ctrl+b → d to detach, tmux attach later to come back

Mini Challenges

Conclusion: Practice the Ctrl+Z/fg round trip, three parallel jobs, and file output.

Linny-senpai: Knowledge sticks when your fingers move. Try these three.

Where to try these: Job control is a shell feature, so it does not run in this site's virtual terminal. Use a terminal on your own Linux machine, WSL, or macOS. The exercises use sleep, so nothing can be damaged if you get it wrong.

Challenge 1: Ctrl+Z ↔ fg Round Trip

Task: Run sleep 30. Pause it partway, run another command, then bring it back.

Show Hint 1 (Direction)

Use the key that pauses, not the one that terminates. After pausing, check the state in a list before returning to it.

Show Hint 2 (Command name)

Pause with Ctrl+Z. Check with jobs. Return with fg.

Show Answer
$ sleep 30
# About 5 seconds in, press Ctrl+Z

$ jobs
# → Should show [1]+ Stopped sleep 30

$ ls    # try another command

$ fg    # return to sleep, finish out the remaining time

Challenge 2: Three Parallel Jobs

Task: Start three commands in the background from the start. Then terminate only the middle one.

Show Hint 1 (Direction)

There is a way to send a command to the background as you launch it. Before terminating one, confirm its number in the job list.

Show Hint 2 (Command name)

Background with a trailing &. List with jobs. Terminate with kill %2 — the % matters.

Show Answer
$ sleep 100 &
$ sleep 200 &
$ sleep 300 &

$ jobs    # → all three [1] [2] [3] should appear

$ kill %2 # kill just the middle one

$ jobs    # → [2] should now be gone

Challenge 3: Background With File Output

Task: Run a command that produces output in the background. Collect the output in a file so it never mixes with other commands' output.

Show Hint 1 (Direction)

Backgrounding alone still lets output interrupt your prompt. Recall the syntax that changes where output goes.

Show Hint 2 (Command name)

Redirect with > filename 2>&1. Background with a trailing &. Read the collected output with cat.

Show Answer
$ ls -R / > result.log 2>&1 &
[1] 12345

$ jobs              # Running
$ tail result.log   # output accumulates in the file

# When the job finishes, you'll see something like:
# [1]+  Done    ls -R / > result.log 2>&1

Because of 2>&1, the "permissionThe read / write / execute access rules set on a file or directory. denied" errors from unreadable directories go to the file as well. Your screen stays clean.

Lina: Got it! The safety of Ctrl+Z is huge — I'll never kill vim with Ctrl+C again.
Linny-senpai: That's the experience of "learning job control." Every day in the shell gets a little smoother from here.

Today's Three-Line Summary

  • Ctrl+Z pauses and frees the terminal, fg brings it back, bg keeps it running behind — never accidentally kill vim with Ctrl+C again
  • Always reference jobs with % (kill %1kill 1) — getting PID and job number mixed up can take down init
  • For background long-runners, make & + > file 2>&1 a habit, and reach for nohup / disown / tmux when you need to survive logout

Next Reading

Share this article

Next steps