1. Overview
As we know, a program in execution generally takes an input, processes it, and gives us the appropriate output. Linux, as a multitasking operating system, supports the execution of many processes – basically, programs or commands – as background and foreground jobs.
In this tutorial, we’ll discuss interactive processes and non-interactive processes. Also, we’ll learn what job control is in Linux. We’ll also discuss basic ways to multitask from the command line — something that’s necessary when running time-intensive programs.
2. Interaction and Job Control
A terminal session initializes and controls interactive processes. In other words, there has to be someone to connect to the system to start these processes; they do not start automatically. These processes can run in the foreground, thereby occupying the terminal that starts the program. We can’t start other applications as long as this process is running in the foreground.
Alternatively, they can run in the background, so that the terminal in which we start the program can accept new commands while the program is running. Such kinds of processes are known as non-interactive processes. While a process runs in the background, the user can do other things in the terminal.
The shell offers a feature called job control that allows easy handling of multiple processes. This mechanism switches processes among the background and foreground jobs. Using this system, programs can also start in the background immediately.
Job control is the ability to move processes or commands between the foreground and background and to suspend and resume their execution. To implement this, bash introduces the concept of a job, which is essentially a command that one or more processes execute.
The shell uses a few simple data structures in its job control implementation. There is a structure to represent a child process, including its process ID, its state, and the status it returns.
3. Background and Foreground Jobs
A process that connects to the terminal is called a foreground job. A job is said to be in the foreground because it can communicate with the user via the screen and the keyboard.
On the other hand, a process that disconnects from the terminal and cannot communicate with the user is called a background job. If the background job requires interaction with the user, it will stop and wait until establishing a connection to the terminal.
We can place the jobs that do not require interaction from the user as they run (like sorting a large file) in the background. This allows the user to access the terminal and continue to work, instead of waiting for a long job to finish:
3.1. Starting a Job in the Background
We can use the jobs command to list all the jobs that the current shell has invoked. The shell lists the job ID of each job, along with the status (running, stopped, or otherwise), and the command that started the job. The shell considers the most recent job to be the current job, marked with a plus sign.
The commands related to job control will apply to the current job. All other jobs, marked with a minus sign, are previous jobs. Jobs can be referred to by job ID by using the percent sign. Thus, job 1 is referred to as %1, job 2 is %2, and so forth.
To place a job in the background, we can simply add the ampersand character (&) at the end of a shell command.
To sort a file called “foo”, and place the results in a file called “bar”, we can issue the command:
$ sort < foo > bar &
3.2. Suspending a Foreground Job
We can (usually) tell Linux to suspend a job that is currently connected to the terminal by typing Ctrl-Z. The shell will inform us that the process has been suspended, and it will assign the suspended job a job ID.
There’s a big difference between a suspended job and a job running in the background. When a suspended job is stopped, no processing takes place for that job until it gets run, either in the foreground or in the background.
3.3. Placing a Foreground Job into the Background
If we start a job in the foreground and would like to place it in the background, the first thing to be done is to suspend the job with a Ctrl-Z, which frees the terminal:
$ tail -f temp.log
^Z[1]+ Stopped tail -f temp.log
Then, we can issue the command bg to place the suspended job in the background:
$ bg
[1] tail -f temp.log
$ jobs
[1]+ Running tail -f temp.log
The bg command can accept a job ID as an argument. If no job ID is given, bg assumes we are referring to the current (suspended) job.
3.4. Bringing a Background Job to the Foreground
We can reconnect a background job to our terminal with the Linux command fg.
The fg command will accept a job ID as an argument. Make sure to include the percent sign:
$ fg %2
This command will bring job 2 into the foreground. If no job ID is given, fg will assume we’re referring to the current (suspended) job.
3.5. Starting a Suspended Job
If we have a suspended job that we’d like to resume running, we must first decide whether we want it to run in the foreground or the background. Once we’ve found the job ID of the suspended job with the jobs command, we can then use bg (to run the job in the background) or fg (to run the job in the foreground).
4. Signals
Signals are standardized messages sent to a running program to trigger specific behavior, such as quitting or error handling. Common uses of signals are to suspend, terminate, or kill a process.
We can suspend the execution of a background process with Ctrl-Z, which sends the signal SIGTSTP:
$ tail -f temp.log
^Z[1]+ Stopped tail -f temp.log
$ jobs
[1]+ Stopped tail -f temp.log
We can terminate a background process by sending it to the foreground and then terminating it with Ctrl-C, which sends the signal SIGINT.
Of course, we can use these Linux controls to stop or terminate the execution of a process. But, a more direct approach to terminating a background process is to use the kill command. It doesn’t use job IDs — instead, it uses PIDs. The kill -9
$ jobs
[1]+ Running tail -f temp.log
$ kill -9 97
[1]+ Killed tail -f temp.log
By default, the kill command sends the kill signal, SIGKILL, an immediate termination.
Similar to Ctrl-Z, we can also use kill to send a stop signal, SIGSTOP, which is a process suspend signal:
$ jobs
[1]+ Running tail -f temp.log
$ kill -19 152
[1]+ Stopped (signal) tail -f temp.log
$ jobs
[1]+ Stopped (signal) tail -f temp.log
5. Conclusion
In this article, we got an understanding of interactive and non-interactive processes in Linux. We also discussed some of the operations we can perform with foreground and background processes. In the same context, we also learned different signals corresponding to some of the common Linux commands and controls that the kernel sends.