Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
CLI: Job Control in ZSH and Bash

Job Control in ZSH and Bash

All processes in ZSH/Bash under job control are in 3 states: foregrounded, backgrounded and suspended.

# run command in the foreground
command
# run commend in the background
command &
# show the list of jobs ([job-id] priority status command) 
jobs

Once we are running the command, we can suspend by sending the SIGTSTP signal using the keyboard:

Ctrl + Z

It will return us to the shell. At this point can do a few things (note that kill is the shell built in kill not the unix kill, which can be accessed via command kill ):

# foreground the job 1 (return it to the foreground)
fg %1
# background the job 2 (make it continue in the background)
bg %2
# kill the job 3 (sends SIGTERM, not like Ctrl + C which sends SIGINT)
kill %3
# suspend the job 4 (equal to Ctrl + Z)
kill -TSTP %4
# continue the job 5 (equal to bg %5)
kill -CONT %5
# show all running jobs
jobs -r
# show all stopped jobs
jobs -s
# show all jobs
jobs
# show all jobs with process ids
jobs -l
# show all jobs with process group ids
jobs -p
# only in ZSH, show all jobs with the directory the started in
jobs -d
# show status about 1 job
jobs %6
# the above flags can be combined to filter for specific jobs

Or (using prefix search), which only works with fg or bg, but not kill:

fg %command
bg %command

There are some shortcuts like:

# foreground the most recent backgrounded job
%
# same thing as above
%+
# foreground the second most recent backgrounded job
%-

But for best portability across commands, use the job numbers %n where n is the job number.

In ZSH, if you use try to suspend a function operation, it will fork the shell. That function will now be in a totally different process, so any mutation side effects will not be reflected in your shell. This is good of course, because functions should be pure.

To send a signal to all jobs, or kill all of them, use this function:

: '
killjobs - Run kill on all jobs in a Bash or ZSH shell, allowing one to optionally pass in kill parameters

Usage: killjobs [zsh-kill-options | bash-kill-options]

With no options, it sends `SIGTERM` to all jobs.
'
killjobs () {

    local kill_list="$(jobs)"
    if [ -n "$kill_list" ]; then
        # this runs the shell builtin kill, not unix kill, otherwise jobspecs cannot be killed
        # the `$@` list must not be quoted to allow one to pass any number parameters into the kill
        # the kill list must not be quoted to allow the shell builtin kill to recognise them as jobspec parameters
        kill $@ $(sed --regexp-extended --quiet 's/\[([[:digit:]]+)\].*/%\1/gp' <<< "$kill_list" | tr '\n' ' ')
    else
        return 0
    fi

}
@casper

This comment has been minimized.

Copy link

commented Jun 19, 2018

This is a good reference. May I suggest also disown to remove a process from the job control list. Can be useful sometimes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.