# jobs — Run, Suspend and Background Shell Jobs

> Shell job control with jobs, fg, bg, &, Ctrl+Z and disown: run, suspend, resume and detach processes inside an interactive shell.

Source: https://www.jpkc.com/db/en/cheatsheets/shell-system/jobs/

<!-- PROSE:intro -->
When a command takes a while to run, you don't want it locking up your terminal – that is exactly what the shell's job control is for. With `&`, `Ctrl+Z`, `jobs`, `fg`, `bg` and `disown` you launch processes in the background, suspend them, pull them back, or detach them from the terminal entirely. This guide walks you through the builtins and job specifiers that keep several tasks under control at once, from a quick `sleep 300 &` to a bounded parallel queue.
<!-- PROSE:intro:end -->

## Starting Jobs

`<command> &` — Run a command in the background. The shell prints '[n] pid' and returns immediately.

```bash
sleep 300 &
```

`<command1> & <command2> & <command3> &` — Start multiple background jobs in one line.

```bash
make build & make docs & make test &
```

`( <command> & )` — Run a command in a subshell so it survives the parent without showing in jobs.

```bash
( long-running-task & )
```

`<command> &!` — Zsh: start in background AND immediately disown — survives shell exit, no SIGHUP.

```bash
long-running-task &!
```

`<command> |&` — Background a pipeline that includes stderr (bash 4+, zsh).

```bash
make 2>&1 | tee build.log &
```

## Suspending Jobs

`Ctrl+Z` — Send SIGTSTP to the foreground process — suspends it and returns control to the shell.

```bash
vim file.txt   # press Ctrl+Z to suspend, edit again with fg
```

`Ctrl+Y` — Send SIGTSTP only when the process tries to read input (delayed suspend, BSD/macOS only).

```bash
less bigfile   # Ctrl+Y suspends on next read
```

`kill -STOP <pid>` — Suspend any process by PID (not just the foreground one).

```bash
kill -STOP 4242
```

`kill -CONT <pid>` — Resume a stopped process by PID — the counterpart to -STOP.

```bash
kill -CONT 4242
```

## Listing Jobs

`jobs` — List all jobs in the current shell with their numbers, status, and command.

```bash
$ jobs
[1]+  Running                 sleep 300 &
[2]-  Stopped                 vim file.txt
```

`jobs -l` — List jobs including their PID.

```bash
jobs -l
```

`jobs -p` — Print only PIDs of jobs (one per line) — handy for scripting.

```bash
jobs -p | xargs kill
```

`jobs -r` — List only running jobs.

```bash
jobs -r
```

`jobs -s` — List only stopped jobs.

```bash
jobs -s
```

`jobs -n` — List only jobs whose state changed since the last notification.

```bash
jobs -n
```

`jobs %<n>` — Show status of one specific job.

```bash
jobs %1
```

## Job Specifiers

`%<n>` — Refer to job number n (the number shown by 'jobs').

```bash
fg %2
```

`%%   or   %+` — The current job (most recently suspended or backgrounded). Implicit target of 'fg' / 'bg' without arguments.

```bash
fg %%
```

`%-` — The previous job (the one before %+).

```bash
fg %-
```

`%<string>` — Job whose command begins with the given string.

```bash
fg %vim
```

`%?<string>` — Job whose command contains the given string anywhere.

```bash
kill %?make
```

## Foreground & Background

`fg` — Bring the current (most recent) job back to the foreground.

```bash
fg
```

`fg %<n>` — Bring job number n back to the foreground.

```bash
fg %1
```

`bg` — Resume the current stopped job in the background (continue running, but no terminal input).

```bash
Ctrl+Z, then 'bg' to keep running detached
```

`bg %<n>` — Resume a specific stopped job in the background.

```bash
bg %2
```

`%<n>` — Bare job specifier brings that job to the foreground (shortcut for 'fg %n').

```bash
%1
```

`%<n> &` — Bare job specifier with '&' resumes it in the background (shortcut for 'bg %n').

```bash
%1 &
```

## Killing & Signaling Jobs

`kill %<n>` — Send SIGTERM to a job by job number.

```bash
kill %1
```

`kill -9 %<n>` — Force-kill (SIGKILL) a job that won't terminate.

```bash
kill -9 %2
```

`kill -<signal> %<n>` — Send any signal by name or number to a job.

```bash
kill -HUP %1
```

`kill %<string>` — Kill the job whose command starts with <string>.

```bash
kill %make
```

`kill $(jobs -p)` — Send SIGTERM to all current jobs of the shell.

```bash
kill $(jobs -p)
```

## Detaching Jobs (disown)

`disown` — Remove the most recent job from the shell's job table — it keeps running but is no longer tracked.

```bash
long-task & disown
```

`disown %<n>` — Detach a specific job by number.

```bash
disown %2
```

`disown -h %<n>` — Keep the job in the table but mark it to NOT receive SIGHUP when the shell exits.

```bash
disown -h %1
```

`disown -a` — Detach all jobs from the shell.

```bash
disown -a
```

`disown -r` — Detach only running jobs (leave stopped ones in the table).

```bash
disown -r
```

`shopt -s huponexit` — Bash: send SIGHUP to all jobs when the shell exits (default is OFF — they survive).

```bash
shopt -s huponexit
```

`setopt nohup` — Zsh: do NOT send SIGHUP to jobs when the shell exits.

```bash
setopt nohup
```

## Waiting for Jobs

`wait` — Block until all background jobs of the current shell have finished.

```bash
task1 & task2 & task3 & wait
```

`wait %<n>` — Wait for one specific job to finish — exit status of wait equals the job's exit status.

```bash
long-task & wait %1; echo "exited $?"
```

`wait <pid>` — Wait for a specific PID (also background jobs not in the current shell, on bash 5.1+).

```bash
wait 4242
```

`wait -n` — Wait for ANY single background job to finish (bash 4.3+, zsh). Useful for parallel queues.

```bash
for i in 1 2 3; do task $i & done; wait -n
```

`wait -f <pid>` — Wait until the process actually terminates, even if its parent already reaped it (bash 5.1+).

```bash
wait -f 4242
```

## Patterns & Pitfalls

`command > out.log 2>&1 &` — Background a command and redirect both stdout and stderr to a file (otherwise stray output appears in the terminal).

```bash
make build > build.log 2>&1 &
```

`command < /dev/null > out.log 2>&1 &` — Fully detach from terminal stdin/stdout — no SIGTTIN/SIGTTOU when the terminal is closed.

```bash
long-task < /dev/null > out.log 2>&1 &
```

`set -m   /   set +m` — Enable or disable job control. Off by default in scripts — turn on with 'set -m' to use %n inside a script.

```bash
set -m; long-task & fg %1
```

`set -b` — Bash: notify about job state changes IMMEDIATELY instead of only before the next prompt.

```bash
set -b
```

`$!` — PID of the last backgrounded process — pair it with 'wait' or 'kill' to track a specific job.

```bash
long-task & echo $! > task.pid
```

`trap 'kill $(jobs -p) 2>/dev/null' EXIT` — Clean up: kill all child jobs when the shell or script exits.

```bash
trap 'kill $(jobs -p) 2>/dev/null' EXIT
```

## Common Recipes

`Ctrl+Z, bg, disown` — Promote a foreground command into a fully detached background process — survives logout.

```bash
tail -f big.log   # Ctrl+Z
bg
disown
```

`for f in *.mp4; do ffmpeg ... "$f" & done; wait` — Run a batch in parallel and wait for all to finish.

```bash
for f in *.mp4; do ffmpeg -i "$f" "${f%.mp4}.webm" & done; wait
```

`Parallel queue with -n (max parallel)` — Process work items with a bounded number of parallel jobs.

```bash
max=4; for i in {1..20}; do (( $(jobs -r | wc -l) >= max )) && wait -n; task $i & done; wait
```

`kill %1 && wait %1 2>/dev/null` — Stop a job and wait for the shell to fully reap it (silences the 'Terminated' notice).

```bash
kill %1 && wait %1 2>/dev/null
```

<!-- PROSE:outro -->
## Conclusion

Job control turns a single shell into a small process manager: `jobs` shows you what is running, `Ctrl+Z` followed by `bg` pushes a stuck command into the background, and `fg` pulls it back. The catch is that background jobs are tied to your terminal. Quit the shell or log out and, by default, they receive a SIGHUP and die – taking any unsaved work with them. To make a job survive a logout, detach it with `disown -h`, or start it under `nohup`, `screen` or `tmux` from the outset. And remember: these builtins only work in an interactive shell; inside scripts you must enable job control first with `set -m`.

## Further Reading

- [GNU Bash: Job Control](https://www.gnu.org/software/bash/manual/html_node/Job-Control.html) – the canonical Bash reference for foreground/background jobs and signals
- [Wikipedia: Job control (Unix)](https://en.wikipedia.org/wiki/Job_control_(Unix)) – background on suspending, resuming and detaching processes under Unix
<!-- PROSE:outro:end -->

## Related Commands

- [bash](https://www.jpkc.com/db/en/cheatsheets/shell-system/bash/) – the Bourne-Again shell that hosts the job-control builtins
- [kill](https://www.jpkc.com/db/en/cheatsheets/shell-system/kill/) – send signals to processes and jobs (SIGTERM, SIGKILL, SIGCONT)
- [nohup](https://www.jpkc.com/db/en/cheatsheets/shell-system/nohup/) – immunise processes against SIGHUP so they survive logout

