Bash Background Process Management

There are many times when a Bash developer or user will want to run a process in the background, either from the command line or from inside a bash script, and then handle that same process again later. There are various command line tools which allow one to do so. Being able to start, manage and destroy background processes is a requirement for many more advanced level tasks, especially in the areas of advanced scripting and process control.

In this tutorial you will learn:

  • How to start, handle and/or manage, and destroy background processes
  • What command line tools are available to assist you with Bash process management
  • Examples highlighting the use of background processes at the Bash command line
Bash Background Process Management

Bash Background Process Management

Software requirements and conventions used

Software Requirements and Linux Command Line Conventions
Category Requirements, Conventions or Software Version Used
System Linux Distribution-independent
Software Bash command line, Linux based system
Other Any utility which is not included in the Bash shell by default can be installed using sudo apt-get install utility-name (or yum install for RedHat based systems)
Conventions # – requires linux-commands to be executed with root privileges either directly as a root user or by use of sudo command
$ – requires linux-commands to be executed as a regular non-privileged user

Example 1: Starting a process in the background and bringing it back to the foreground

$ sleep 1000 &
[1] 25867
$ fg
sleep 1000


Here we started a 1000 second sleep process in the background. If we want to put a process in the background, we can use the ampersand (&) sign behind any command. This will place the process in the background, and reports back the PID (Process ID, an identifier number which identifies any process running on a Linux machine). In this example, the PID is 25867. Note that the process keeps running when it is placed in the background, which gives us the best of both worlds; the process is executing, and we get our command line back in the meantime! Great.

We next place the process back in the foreground (as if there never was a background instruction) by using the fg (i.e. foreground) command. The result is that we see what process is being placed in the foreground again (i.e. sleep 1000) and our command prompt does not return as we placed the sleep back in the foreground and the command prompt will only return when the 1000 second sleep is done.

Let’s say that we placed the sleep 1000 in the background, did other work for 500 seconds, and then executed fg… How long would the sleep still run? If you guess (or knew) 500 seconds, then you’re correct. The first 500 seconds were spent running as a background process, and the second 500 will be as a foreground process.

Note also that if you terminate the shell your command will terminate – whether it is running in the background, or in the foreground (unless you disowned it, more on this in the next example).

Example 2: Disowning a process

$ sleep 1000 &
[1] 26090
$ disown %1
$ 

Here we started another 1000 second sleep, and we were informed of the PID of the background process as before. Next we executed disown %1, referring to the first background process (as also indicated by the [1] before the PID!), and instructing Bash to disown (disassociate) this process from the current shell. It is not that it will be disassociated from the current user (and for example ps -ef | grep sleep | grep -v grep will indeed still show your userID), but rather from the current shell session. Look:

$ sleep 1000 &
[1] 26214
$ disown %1
$ ps -ef | grep sleep | grep -v grep
roel     26214 26120  0 13:13 pts/3    00:00:00 sleep 1000
$ exit

Then, opening a new shell and re-executing the ps we can see that the command is still there and is now attached to PPID (Parent PID) 1 instead of 26120 as parent PID:

$ ps -ef | grep sleep | grep -v grep
roel     26214     1  0 19:48 ?        00:00:00 sleep 1000

It is as if the shell is still running (note the 26214 PID still being active/associated with the running sleep), however the active command line part of it is gone!

Great, so this gives us a way to disassociate processes from the current shell, and thereby ensure they keep running when our shell session is closed.

Example 3: Placing a command into the background

$ sleep 1000
^Z
[1]+  Stopped                 sleep 1000
$ bg %1
[1]+ sleep 1000 &
$ 

Here we started a sleep 1000 in the foreground (no & was used), and the interrupted that process with the keyboard shortcut CTRL+z. Note that while the output says ^Z (and ^ is a symbol to indicate CTRL), the Z is actually a lowercase z, so you do not need to use SHIFT, just CTRL+z.

Note that the process actually stopped, it did not continue running. Now we have placed the process in the background, and paused it. To let this process continue running now, we have two options; fg %1 – i.e. place the process indicated by [1] back into foreground and continue running normally, or bg %1 which will resume the process, but in the background. In the example we can see the latter, and our command prompt returns as expected.

Note that the above can be slightly augmented with disown, matching an often used way to handle a process when using a remote server. Let’s say you are connected via SSH to a remote server and started a large job, for example a backup or report generation. Now you would like to leave your office for the day, but are unsure whether your SSH connection will stay live all night, and even whether your computer will not hibernate or similar. Any of these actions could jeopardize the running job!

In that case, you can do the following;

$ sleep 1000
^Z
[1]+  Stopped                 sleep 1000
$ bg %1
[1]+ sleep 1000 &
$ disown %1
$ 


And happily and safely walk away from your computer (after locking it ;), as you can rest assured that – even if your SSH connection fails, or your computer hibernates, or the cleaning lady knocks out the power cord – that your job will remain running. As the process was disowned/disassociated from the current shell session, it will continue running even if the current shell session is somehow terminated.

One small caveat is that you cannot use fg in the morning to bring the job back to the foreground, even if your SSH connection and shell never terminated/failed:

$ fg 
bash: fg: current: no such job
$ fg %1
bash: fg: %1: no such job

When it’s disowned, it’s disassociated and gone! The job will still be running in the background though, and you can even kill it using it’s PID (as can be observed from ps -ef | grep your_process_name | grep -v grep.

Example 4: Multiple background processes and terminating processes

First we start two processes in the background using our trusted sleep 1000 example:

$ sleep 1000 &
[1] 27158
$ sleep 1000 &
[2] 27159

We can see here that two background processes ([1] and [2], with PID’s 27158 and 27159 respectively) were started. Next, we kill the first process:

$ kill %1
$ 
[1]-  Terminated              sleep 1000
$ 

That was straightforward/easy, right? One question one may ask is why the Terminated information does not show immediately (an extra enter press is required as you can see) and the reason is that the process was not terminated before the command line was returned. As part of the work that is done every time before a new command line is shown is to report on a number of statuses, including background process status if required. Thus, when enter was pressed again (indicated by the empty $ line, a report of the terminated process is shown.

Example 5: One done before the other

Let’s again start two processes, but this time the second process will sleep only for 3 seconds:

$ sleep 1000 &
[1] 27406
$ sleep 3 &
[2] 27407
$

After about 5 seconds, pressing enter, we will see:

$
[2]+  Done                    sleep 3

What will happen now if we use fg in this case without the original [1] specifier?

$ fg
sleep 1000
^Z
[1]+  Stopped                 sleep 1000
$ 


The first process will continue! This is also the case if the reverse procedure were used:

$ sleep 10 &
[1] 27346
$ sleep 1000 &
[2] 27347
$ 
[1]-  Done                    sleep 10
$ fg
sleep 1000
^Z
[2]+  Stopped                 sleep 1000

The fg command will always take the last command which was placed into the background (and which was not completed yet), and place it into the foreground again.

Conclusion

In this article, we looked at various commands, including bg, fg and the background Bash idiom ampersand & which can be placed after any command to place that command into the background. We also explored the user of the kill command and looked at how to address various background processes using the % Bash idiom with a matched background process number like %1 for [1] etc.

If you would like to learn more about Bash in general, have a look at the Useful Bash Command Line Tips and Tricks Examples series.

Enjoy your new found Bash skills, and if you do something cool with background processes, please leave us a comment below!



Comments and Discussions
Linux Forum