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!
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
zsh as the
jobscommands 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.
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!')
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 + 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.
bg command will take the suspended job and push it to the background, thus resuming it’s operation:
# Bash $ bg + ( sleep 900 && echo 'done!' ) & # Z shell $ bg  + continued ( sleep 60 && echo 'done!'; )
After the allotted
sleep time has passed, we should be greeted with the
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 + Stopped ( sleep 900 && echo 'done!' ) ~ $ bg + ( sleep 900 && echo 'done!' ) & # Z shell $ (sleep 900 && echo 'done!') ^Z zsh: suspended ( sleep 900 && echo 'done!'; ) ~ $ bg  + 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  + 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-Zand then issuing the
bg command again. You could also simply kill the process with
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!') &  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
fg to target a specific job.
Let’s create three different background processes so we can see
jobs in action:
$ (sleep 900 && echo 'done!') &  236156 ~ $ (sleep 600 && echo 'done!') &  236165 ~ $ (sleep 300 && echo 'done!') &  236173
Now that we have some jobs running in the background, let’s run the
jobscommand to see a list of everything:
# Bash $ jobs  Running ( sleep 900 && echo 'done!' ) & - Running ( sleep 600 && echo 'done!' ) & + Running ( sleep 300 && echo 'done!' ) & # Z shell $ jobs  running ( sleep 900 && echo 'done!'; )  - running ( sleep 600 && echo 'done!'; )  + 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  - 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