opscape

Processes and jobs · bash builtin

fg

Bring a background or stopped job into the foreground, so it gets the terminal and the shell waits for it.

fg [JOBSPEC]

5 of 5 examples run in Debian 13.7 on 2026-10-31 · manual: bash(1)

fg is half of the interactive job-control pair with bg. The everyday move: you are in vim or less, press Ctrl-Z, the shell prints [1]+ Stopped vim notes.txt and gives you a prompt; you run a command or two, then type fg and you are back in the editor exactly where you were. Ctrl-Z sends the TSTP signal, which stops the foreground job; fg sends CONT and hands it the terminal again, and the shell waits until it finishes or is stopped again.

Without an argument fg picks the current job, marked + in jobs. Give %2, %vim or %?notes to choose another. With several stopped editors, jobs then fg %N is the usual routine.

fg needs job control, which interactive shells have and scripts do not. In a script (and in these examples, which run under bash -c) fg fails with no job control unless the script runs set -m first. With set -m it works: it resumes the job if stopped and waits for it, returning its exit status. The examples cannot press Ctrl-Z or give a job a terminal, so they stop jobs with kill -TSTP, the same signal.

Examples

fg in a script without job control

sleep 1 &
fg
outputexit 1
/bin/bash: line 2: fg: no job control

Non-interactive shells start with job control off, so fg refuses with no job control and exit status 1. In a script you almost always want wait instead.

Resume a stopped job in the foreground

set -m
(sleep 1; echo "job finished") &
kill -TSTP %1
sleep 0.1
jobs
fg %1
echo "fg returned $?"
output
[1]+  Stopped                 ( sleep 1; echo "job finished" )
( sleep 1; echo "job finished" )
job finished
fg returned 0

set -m turns job control on. kill -TSTP stops the job as Ctrl-Z would; jobs shows it Stopped. fg prints the job's command, resumes it and waits; the job completes and fg returns its exit status.

fg returns the job's exit status

set -m
(sleep 0.5; exit 7) &
fg
echo "fg returned $?"
output
( sleep 0.5; exit 7 )
fg returned 7

With no argument fg takes the current job. Like wait, it returns the job's own exit status (7 here), so fg && echo ok reacts to whether the job succeeded.

Choose a job by name

set -m
sleep 0.5 &
(sleep 0.2; echo "second job done") &
sleep 0.1
fg %sleep
jobs
output
sleep 0.5
second job done
[2]   Done                    ( sleep 0.2; echo "second job done" )

%sleep selects the job whose command starts with sleep, even though it is not the current job. fg waits for it; jobs then reports the other job, which finished in the meantime, as Done.

No job to bring back

set -m
fg
outputexit 1
/bin/bash: line 2: fg: current: no such job

With an empty job table there is no current job: current: no such job, exit status 1.

Common pitfalls

  • Pressing Ctrl-Z and forgetting the job. Stopped jobs use no CPU but keep their memory, open files and locks. bash warns There are stopped jobs on the first exit; a second exit kills them.

  • Expecting fg to work in a script or in ssh host 'cmd' without a terminal. Without job control it fails; use wait to wait for background work.

  • Using fg to wait for a job in a set -m script when its output or input matters: fg gives the job the terminal, which in a script is usually not what you want. wait %1 is clearer.

GNU vs BSD and macOS

The examples above ran the GNU/Linux version. These are the differences that matter on macOS and the BSDs (written from their documentation, not run here).

  • fg and bg are shell builtins, specified by POSIX for shells with job control; they work the same in bash, zsh, ksh and dash on Linux and macOS. The %name and %?text job specs are supported by all of them.

Related