Tooltip #5: Job Control in bash
This is one of those features that fills a role which is almost always better filled by some other more powerful tool, but can nonetheless help you out in a pinch, or is at least a good thing to know about.
You know you can run commands in the background in your shell, right? That thing where a README or tutorial will tell you to run a command with a trailing
&, so you can run other commands in the same shell while that command’s doing its own thing? That little feature fits in with a small group of shell builtins which all work together and collectively do ‘job control’.
The job control commands are
jobs. The other supplementary features are that trailing
& and the
This one you probably know. If you follow a command with a
& at the very end, it will run in the background. No matter how long the program takes to exit, you will immediately see a prompt where you can go on typing commands in the exact same shell environment. If it prints anything, that output will have a little battle with your prompt until you intervene.
If you start a command, and realize it’s not going to exit as quickly as you thought it would, you have a few options. You might reach for the humane instruments of quick process death,
^D to feed an EOF to its stdin, or
^C to send it a ‘INT’ interrupt signal. Another option is to hit
^Z, which functions more like cryogenically freezing the process.
jobs command will show you all the things you have in the background for your current shell session, which includes everything you ran with a trailing
&, and everything you stopped with
^Z. The output of this command will show you something like this.
+ Stopped sleep 3 - Running sleep 3 &
Here, the job will be ‘Running’ if it’s active and in the background, and ‘Stopped’ if it’s been stopped with
Also, you can dereference one of those job numbers using
% with the
$ kill %1 + Stopped sleep 3 $ jobs + Terminated: 15 sleep 3
You can bring one of those background jobs listed in
jobs back into the foreground with
fg. You can pass
fg a job number if you’ve got multiple in the background, otherwise it will default to the last job you interacted with (marked by the
+ in the jobs output). This will automatically resume the job if it’s in the ‘Stopped’ state.
bg command will take a job that’s in the ‘Stopped’ state and resume it, but keep it in the background.
^Z key will stop a job, taking a job running in the foreground to running in the background takes two steps: first, you hit
^Z, then you do a
These job control features are built into the shell, and are associated with a specific shell session (as far as I know). Typically, if you think you’ll need multiple things running at once before actually kicking off a command, you should reconsider your options before reaching for these rather primitive shell features. I hear
tmux is a pretty good option (but still haven’t learned much of it myself :/ ).
Also, a program is free to do whatever it wants in response to a
SIGTSTP, the signal sent to a process when you hit
^Z. Sometimes a program will misbehave in strange ways. Sometimes it will so expected-but-unfortunate things like kill a download that you actually wanted to keep running in the background.
However, one thing that background jobs are more consistently useful for is to keep an editor like
vim open on a file in the background. To move from a foreground editor back to the shell you opened it in, hit
^Z, and you can move back into your editor exactly where you left off with a
I found this article called “The TTY Demystified” to be super interesting and helpful to understand some of these strange job control mechanisms (and more). It goes through an abridged history of why all the layers of software that make up a terminal work and interact the way they do, and into detail on how the mechanisms actually work, and what about them is user-configurable. Highly recommended!