Job Control in Linux using bg, fg and jobs Commands

Running Commands in the Foreground

When running a command from the bash shell prompt, unless you specify otherwise, the command runs in the foreground. The bash shell waits for the foreground command to terminate before issuing another prompt, and anything typed at the keyboard is generally read as stdin to this command.

Running Commands in the Background as Jobs

In contrast, any command you specify can also be run in the background by appending the ampersand character (&) to the command line. Generally, only long-running commands that do not require input from the keyboard, and do not generate large amounts of output, are appropriate for backgrounding. When the bash shell backgrounds a command, the command is referred to as a job and assigned a job number.

In the following example, einstein is performing a search of his entire filesystem for files which are larger than 1 megabyte in size. Because he expects this command to run a while, he redirects stdout to a file, throws stderr away, and runs it as a background job.

$ find / -size +1024k > bigfiles.txt 2> /dev/null &
[1] 7022

After starting the job in the background, the bash shell reports two pieces of information back to einstein. The first is the job number, reported in square brackets. The second is the process ID of the backgrounded job. In this case, the job is job number 1, and the process ID of the find command is 7022.

While this command is running in the background, einstein decides he would also like to find all files owned by him which he has not modified in two week. He composes the appropriate find command, and again backgrounds the job.

$ find / -user einstein -and -mtime +14 > oldfiles.txt 2> /dev/null &
[2] 7023
[1] Exit 1 find / -size +1M >bigfiles.txt 2>/dev/null

Again, bash reports the job number (2) and the process ID of the second find command (7023). The second message from the bash shell is notifying einstein that job number one has finished. The bash shell reports that it has exited with a return code of 1 (as opposed to being killed by a signal), and redisplays the command line to remind einstein of what he had run. The bash shell does not report immediately when jobs die, but waits until the next time it interprets a command line.

By the time einstein has digested all of this, he suspects his second job has finished as well. He simply hits the RETURN key (so that bash will “interpret” the empty command line). The bash shell similarly reports his now finished job number 2.

$
[2]+ Exit 1              find / -user einstein -and -mtime +14 >oldfiles.txt 2>/dev/null

Managing Multiple Jobs

The user einstein, like the user maxwell, is often performing physics calculations that take a long time to execute. He starts several different versions of the simulation, backgrounding each.

$ ls
bin sim_a sim_b sim_c sim_d
$ ./sim_a &
[1]  7309
$ ./sim_b &
[2]  7311
$ ./sim_c &
[3]  7313
$ ./sim_d &
[4]  7315

Listing Current Jobs with jobs

The user einstein can use the jobs builtin command to report all of his currently running jobs.

$ jobs
[1]    Running             ./sim_a &
[2]    Running             ./sim_b &
[3]-   Running             ./sim_c &
[4]+   Running             ./sim_d &

Each of his background jobs are listed, along with the job number. The most recently handled job is referred to as the current job, and is decorated by the jobs command with a “+”.

Bringing a Job to the Foreground with fg

A backgrounded job can be brought back to the foreground with the fg builtin command. The fg command expects a job number as an argument, or if none is supplied, will foreground the current job.

$ fg 3
./sim_c

The job sim_c is now running in the foreground. As a consequence, the shell will not issues another prompt while the process is still running.

Suspending the Foreground Job with CTRL-Z

We had previously introduced the CTRL-Z control sequence as a method of suspending processes. Now, by watching the output of the bash shell closely as einstein suspends the foreground command, we see that the bash shell treats any suspended foreground process as a job.

$ fg 3
./sim_c
CTRL-Z

[3]+ Stopped         ./sim_c
$ jobs
[1] Running         ./sim_a &
[2] Running         ./sim_b &
[3]+ Stopped        ./sim_c
[4]- Running        ./sim_d &
controlling jobs in linux using bg fg jobs

When suspended (or, to use the shell’s terminology, stopped), the process is assigned a job number (if it did not already have one) and backgrounded. The jobs command reports the job as a “Stopped” job, and the ps command confirms that the process is in the stopped state.

Restarting a Stopped Job in the Background

A stopped job can be restarted in the background with the bg builtin command. Like the fg command, the bg command expects a job number as an argument, or, if none is provided, uses the current job.

In the following, einstein restarts his stopped job in the background.

$ bg 3
[3]+ ./sim_c &
$ jobs
[1]    Running             ./sim_a &
[2]    Running             ./sim_b &
[3]-   Running             ./sim_c &
[4]+   Running             ./sim_d &

Now job number 3 is again in the running state.

Killing Jobs

The kill command, which is used to deliver signals to processes, is implemented as a shell builtin command. (Confusingly, another version is also found in the filesystem, /bin/kill. You are probably using the shell builtin version instead). As a result, it is aware of any jobs that the shell is managing.

When specifying which process should receive a signal, the process’s job number (if it has one) can be specified in lieu of its process ID. To distinguish the two, job numbers are preceded by a percent character (%), as in the following example.

$ jobs
[1]    Running             ./sim_a &
[2]    Running             ./sim_b &
[3]-   Running             ./sim_c &
[4]+   Running             ./sim_d &
$ kill 2 􏰀
-bash: kill: (2) - Operation not permitted

Here, einstein mistakenly used the syntax for specifying a process ID, instead of a job number. Because he does not own the process with process ID number 2, the command failed.

$ kill %2 􏰁
$
[2] Terminated       ./sim_b

Here, einstein used the correct syntax for specifying a job number, and the signal was delivered to the sim_b process.

$ jobs
[1]    Running             ./sim_a &
[3]-   Running             ./sim_c &
[4]+   Running             ./sim_d &

Conclusion

The following table summarizes commands and techniques for managing jobs within the bash shell.

Command Action
jobs List all jobs
fg [N] Bring background job N to the foreground (by default, the “current” background job).
CTRL-Z Suspend and background the current foreground command
bg [N] Start stopped background job N (by default, the “current” background job).
kill %N Terminate background job N (by sending the SIGTERM signal).