Add background jobs to your shell prompt
Tags: bash, shell, linux, terminal
Published: 2021-02-20 10:24:12

If you know what are background processes, you can directly proceed to see [Setting the prompt](#setting-prompt).

### Background processes

Whenever we execute a time taking command, we don't see the prompt till the time command finishes. For example, when we execute `sleep 5s`, shell will do nothing for 5 seconds but wait for the command (`sleep`) to finish. After 5 seconds, we will see the prompt again.

Many times, commands are not worthy to wait till they finish their processing. For example, when you are compiling a project and it takes about a minute to complete. You can run the build in background by using `&` at the end of command and you will be notified when background job is completed.
```
chinmay@CC-T480:~$ sleep 5 &
[1] 3683711
chinmay@CC-T480:~$ # After 5 seconds when we press Enter
[1]+  Done                    sleep 5
chinmay@CC-T480:~$ 
```

Here what we did was put `sleep 5` task in background and we got the background process ID that is `3683711`. After 5 or more seconds when we enter a new command just press Enter, we see that the background job `sleep 5` is completed by seeing `Done sleep 5`.

When building a project we can send the build process in background and while waiting for it to complete, we can do some other task. If we are using `make` to build a project and it takes about a minute to complete, we can use `make >/dev/null 2>&1 &` to build in background and not display any info/error logs while also making the shell prompt usable to give other commands.

We can also stop a process by hitting `Ctrl-Z` and this will also send the task in background. But in this case, task will not run in background but will be stopped until resumed by command `fg` in same terminal. We can see the background tasks by command `jobs`.
```
03:26:34 $ sleep 10
^Z
[1]+  Stopped                 sleep 10
03:26:36 $ jobs
[1]+  Stopped                 sleep 10
03:26:38 $ fg
sleep 10
03:26:45 $ jobs
03:26:47 $ 
```  
Another common use of sending task to background is while using `vim` or other terminal based editor. When we need to run some commands in terminal, we can just hit `ctrl-z` in normal mode and `vim` will be stopped. This way we can have our terminal prompt for running commands. When done with terminal, we can switch back to `vim` by `fg` command.

### Setting the prompt
<a name="setting-prompt"></a>

Bash prompt can be set by setting the environment variable `PS1`. We will update this variable to get number of background jobs in our prompt.

If we see manual page for `bash`, we can see that it says we can use `\j` to show number of jobs
```
\j     the number of jobs currently managed by the shell
```
But most of the times we have 0 jobs running in background and displaying a 0 every time is not so tidy approach.

We can use a simple bash command to print the jobs in the prompt if they are more than 0.
```sh
[ \j -gt 0 ] && echo \j
```
Here `\j` is the number of background jobs. What we are doing is checking if it's greater than 0, if yes, then print (`echo`) in the prompt else not.

A simple shell prompt including the current directory and number of background processes can be like
```
chinmay@CC-T480:~/Downloads$ PS1="\w\$([ \j -gt 0 ] && echo [\j]) $ "
~/Downloads $ sleep 10
^Z
[1]+  Stopped                 sleep 10
~/Downloads[1] $ sleep 15
^Z
[2]+  Stopped                 sleep 15
~/Downloads[2] $ vi

[3]+  Stopped                 vi
~/Downloads[3] $ jobs
[1]   Stopped                 sleep 10
[2]-  Stopped                 sleep 15
[3]+  Stopped                 vi
~/Downloads[3] $ fg 2
sleep 15
~/Downloads[2] $ fg 1
sleep 10
~/Downloads[1] $ fg
vi
~/Downloads $ 
```
Here the number of background processes will be listed inside square brackets.

Checkout [designing a minimal bash prompt](https://dev.to/chhajedji/minimal-and-super-useful-shell-prompt-1g8l).