2026年11月14日

2026年11月14日

Linux Job Control: Using bg, fg, jobs and Ctrl+Z to Switch Jobs

This article is a localized edition of the Japanese original. Read the Japanese original

When you run a long command in a terminal, you cannot type the next command until it finishes. With the job control feature of shells such as bash, you can keep a command running in the background while you do other work, or resume a command you paused partway through.

The output examples in this article were checked with bash 5.2 on Debian 13 as of October 2026. zsh works in much the same way.

Jobs, foreground and background

A command started from the shell (including a series of commands joined by pipes) is called a job. A job is in one of these states:

State Meaning
Foreground Running and holding the terminal. It can receive keyboard input. Only one at a time
Background (Running) Running without holding the terminal. You get the prompt back and can type other commands
Stopped Paused. It does not run until you resume it with fg or bg

These are the operations you use:

Operation What it does
command & Start a command in the background
Ctrl+Z Pause the foreground job
jobs List jobs
fg Move a job to the foreground (resuming it if stopped)
bg Resume a stopped job in the background
kill %number Send a signal to a job (terminate by default)

Run a command in the background (&)

Add & to the end of a command to start it in the background and return to the prompt right away.

$ sleep 300 &
[1] 7
$ echo $!
7

[1] is the job number and 7 is the process ID. $! gives you the process ID of the most recent background process.

Messages printed by background jobs appear directly in the terminal. To keep your screen tidy, send the output to a file.

./backup.sh > backup.log 2>&1 &

Pause a running command (Ctrl+Z)

You can pause a command running in the foreground with Ctrl+Z.

$ vim memo.txt
(press Ctrl+Z in vim)
[1]+  Stopped                 vim memo.txt
$

A stopped job is simply frozen in place; it has not exited. For example, you can drop back to the shell with your editor still open, run a command to check something, and then return to the editor.

Ctrl+C does not pause; it interrupts (terminates) the foreground job.

List jobs (jobs)

$ sleep 300 &
[1] 7
$ sleep 200 &
[2] 8
$ jobs
[1]-  Running                 sleep 300 &
[2]+  Running                 sleep 200 &

The symbol after the number means:

  • +: the current job. It is the target when you run fg or bg without a number
  • -: the job before that

Commonly used options:

Command Shows
jobs -l Process IDs as well
jobs -p Process IDs only
jobs -r Running jobs only
jobs -s Stopped jobs only
$ jobs -l
[1]-     7 Running                 sleep 300 &
[2]+     8 Running                 sleep 200 &

jobs shows only jobs started from that shell. Anything started in another terminal or another SSH session does not appear. Find those with ps or pgrep.

Refer to a job (%)

With fg, bg, kill and similar commands, you refer to a job with %.

Syntax Target
%1 Job number 1
%+ or %% The current job (marked +)
%- The previous job (marked -)
%sleep The job whose command name starts with sleep
%?log The job whose command line contains log

When you refer to a job by name, as in %sleep, and more than one job matches, you get an error. In that case, use the number.

Bring a job back to the foreground (fg)

$ fg %1
vim memo.txt

fg brings the specified job back to the front of the terminal, resuming it if it was stopped. Without a number, it acts on the current job (+).

Resume a stopped job in the background (bg)

If you forgot the & and started a long task, pause it with Ctrl+Z and then move it to the background with bg.

$ tar czf site.tar.gz /var/www/html
(press Ctrl+Z)
[1]+  Stopped                 tar czf site.tar.gz /var/www/html
$ bg %1
[1]+ tar czf site.tar.gz /var/www/html &
$ jobs
[1]+  Running                 tar czf site.tar.gz /var/www/html &

bg acts on stopped jobs. It has no effect on a job that is already running.

If a background job tries to read keyboard input, that job is stopped (jobs shows it as Stopped). For commands that ask for input such as a password, bring them to the front with fg and type there.

Terminate a job (kill)

You can give kill a job instead of a process ID.

$ kill %2
$ jobs
[1]-  Running                 sleep 300 &
[2]+  Terminated              sleep 200

By default kill sends SIGTERM (a request to exit). Only if the job does not respond, force it with kill -KILL %2 (kill -9). You can also terminate stopped jobs with kill.

When a job ends, a notice such as Done (normal exit) or Terminated (ended by a signal) appears the next time the prompt is shown, and the job is removed from the list.

What happens to jobs when the shell closes

Jobs are child processes of the shell, so take care when closing it.

  • If you run exit while there are stopped jobs, the shell prints There are stopped jobs. and does not exit. If you run exit again right away, the stopped jobs are terminated.
  • When an SSH connection drops or you close the terminal window, the shell receives SIGHUP and also sends SIGHUP to running and stopped jobs. Most commands exit when they get it.

To keep work running after you log out, use one of the following.

disown: detach a job that is already running

$ ./import.sh > import.log 2>&1 &
[1] 1234
$ disown %1
$ jobs
$

disown removes the job from the shell's job list so that the shell does not send it SIGHUP when it exits. To keep it in the list, use disown -h %1. For a stopped job, resume it first with bg and then run disown.

nohup: make it survive disconnects from the start

nohup ./import.sh > import.log 2>&1 &

nohup starts the command so that it ignores SIGHUP. If you do not redirect the output, it is written to nohup.out in the current directory.

For longer and more reliable runs

If you want your whole working session to survive an SSH disconnect, use tmux or screen. For processes that should always run on a server, registering them as systemd services instead of using job control also takes care of starting them after a reboot and managing their logs.

Using it in shell scripts

In scripts, the common pattern is to start several tasks at once with & and wait for them to finish with wait.

#!/bin/bash
gzip -k access.log &
gzip -k error.log &
wait
echo "All compression jobs are done"

wait waits until every background process started by that shell has finished. Give it a process ID, as in wait $!, to wait for just that process. Job control is normally disabled in scripts, so build them with & and wait rather than fg and bg.

Summary

  • Start a command in the background with command &; get its process ID with $!
  • Pause with Ctrl+Z, bring to the front with fg, resume in the background with bg
  • List jobs with jobs (-l adds PIDs) and refer to them with %1, %+, %- or %name
  • Terminate with kill %number; the default signal is SIGTERM
  • For work that must continue after logout, use disown or nohup; for long-term use, tmux or systemd

Related articles:

Questions about WordPress? The publisher of this site is based in Japan and replies in Japanese. Contact (Japanese)

お気軽にご相談ください

お見積りへ お問い合わせへ
▲