Saturday, 28 September, 2019 UTC


Summary

Ever run a command that you knew would take a long time to run, and you end up stuck leaving the terminal open eagerly waiting for it to finish? I have and it sucks. Fortunately from the command-line you can push processes to the background and recall them to the foreground with ease!
Getting started
To follow along at home, you don’t necessarily need a Unix-like operating system, but you will need to be running a shell like bash or zsh as the fg, bg and jobs commands are built into the shell and not stand-alone executables.
For the sake of example, we’ll also be using the sleep command to simulate long running commands that lock up the terminal for a period of time.

Recommended Course 📺

👉 Learn Node, a video course by Wes Bos 👈
You'll learn things like user auth, database storage, building a REST API and uploading images in Node.js by building a real world restaurant application.
ⓘ About this affiliate link
Moving a process to the background
If you’re not actively waiting for a long running process to finish executing, let’s start up a long running process to play with:
$ (sleep 60 && echo 'done!') 
The little echo at the end is so we get a response in the terminal without any additional interaction from us. Don’t forget the parentheses to group the commands!
Now that we have a script running and blocking us from doing anything in the current terminal, we can quickly hit CTRL-Z which will suspend the task:
# Bash ^Z [1]+ Stopped ( sleep 60 && echo 'done!' ) # Z shell ^Z zsh: suspended ( sleep 60 && echo 'done!'; ) 
Once stopped or suspended (depending on your shell’s naming) the command is paused and is no longer actively running.
Issuing the bg command will take the suspended job and push it to the background, thus resuming it’s operation:
# Bash $ bg [1]+ ( sleep 900 && echo 'done!' ) & # Z shell $ bg [1] + continued ( sleep 60 && echo 'done!'; ) 
After the allotted sleep time has passed, we should be greeted with the done! message.
Moving a process to the foreground
Now that we know how to throw a process into the background, what about those times we want to check on a long running process, or perhaps we decided that we want to kill it instead of letting it run any longer?
Let’s start up a another long running command, suspend it and send it to the background:
# Bash $ (sleep 900 && echo 'done!') ^Z [1]+ Stopped ( sleep 900 && echo 'done!' ) ~ $ bg [1]+ ( sleep 900 && echo 'done!' ) & # Z shell $ (sleep 900 && echo 'done!') ^Z zsh: suspended ( sleep 900 && echo 'done!'; ) ~ $ bg [1] + continued ( sleep 900 && echo 'done!'; ) 
With the process in the background, we can use fg to recall the last process that was thrown to the background in the current terminal:
# Bash $ fg ( sleep 900 && echo 'done!' ) # Z shell $ fg [1] + running ( sleep 900 && echo 'done!'; ) 
And now we’re right back where we started, with a terminal that’s locked up by a long running process.
From here you could very well throw it back to the background by hitting CTRL-Z and then issuing the bg command again. You could also simply kill the process with CTRL-C.
Starting a process in the background
If you’re lucky enough to remember that a process you’re about to run will take a while, before you actually run it, you can simply append an ampersand & to the command to immediately send it to the background:
$ (sleep 900 && echo 'done!') & [1] 235909 
When you do it this way, you receive the job and process IDs. More on this in the next section.
Handling multiple processes
Everything we’ve discussed thus far has involved interacting with the last process executed. What happens if we end up suspending or backgrounding a bunch of different processes and we want to recall a specific one?
That’s where the jobs command (another shell built-in) comes in, which gives you a list of jobs in the current terminal. Each has an ID that can be used with both bg and fg to target a specific job.
Let’s create three different background processes so we can see jobs in action:
$ (sleep 900 && echo 'done!') & [1] 236156 ~ $ (sleep 600 && echo 'done!') & [2] 236165 ~ $ (sleep 300 && echo 'done!') & [3] 236173 
Now that we have some jobs running in the background, let’s run the jobs command to see a list of everything:
# Bash $ jobs [1] Running ( sleep 900 && echo 'done!' ) & [2]- Running ( sleep 600 && echo 'done!' ) & [3]+ Running ( sleep 300 && echo 'done!' ) & # Z shell $ jobs [1] running ( sleep 900 && echo 'done!'; ) [2] - running ( sleep 600 && echo 'done!'; ) [3] + running ( sleep 300 && echo 'done!'; ) 
To be able to recall the first item to the foreground, we simply pass the job ID to the fg command. Please note though, if you use zsh, you will need to prefix the job ID with a percent sign %:
# Bash $ fg 1 ( sleep 900 && echo 'done!' ) # Z shell $ fg %1 [1] - running ( sleep 900 && echo 'done!'; ) 
Same as before, if you don’t want the command to continue running in the foreground, once recalled, you can throw the job back to the background or kill it completely with CTRL-C.