10 Linux/Unix Bash and KSH Shell Job Control Examples

by on February 2, 2014 · 9 comments· LAST UPDATED March 23, 2014

in Command Line Hacks, Howto

Unix / Llnux shell job control series
Linux and Unix are multitasking operating systems i.e. a system that can run multiple tasks (process) during the same period of time. In this new blog series, I am going to list the Linux and Unix job control commands that you can use for multitasking with the Bash or Korn or POSIX shell.

What is a job control?

Job control is nothing but the ability to stop/suspend the execution of processes (commands) and continue/resume their execution as per your requirements. This is done using your operating system and shell such as bash/ksh or POSIX shell.

Who provides a facility to control jobs?

The Bash / Korn shell, or POSIX shell provides a facility to control jobs.

Say hello to job table

Your shell keeps a table of current jobs, called job table. When you type command the shell assigns a jobID (also known as JOB_SPEC). A jobID or JOB_SPEC is nothing but small integer numbers.

#1: Creating your first Linux/Unix job

I am going to run a command called xeyes that displays two googly eyes on screen, enter:
$ xeyes &
Sample outputs:

Fig.01: Running the xeyes command in the background

Fig.01: Running the xeyes command in the background


I started a job in the background with an ampersand (&). The shell prints a line that looks like the following:

[1] 6891

In this example, two numbers are output as follows

  • [1] : The xeyes job, which was started in the background, was job number 1.
  • 6891 : A process ID of job number 1.

I am going to start a few more jobs:

## Start a text editor, system load average display for X, and sleep command ##
gedit /tmp/hello.c &
xload &
sleep 100000 &
 

#2: List the current jobs

To see the status of active jobs in the current shell, type:
$ jobs
$ jobs -l

Sample outputs:

[1]   9379 Running                 xeyes &
[2]   9380 Running                 gedit /tmp/hello.c &
[3]-  9420 Running                 xload &
[4]+  9421 Running                 sleep 100000 &

A brief description of each field is given below:

FieldValueDescriptionExample(s)
1[1]jobID or JOB_SPEC - Job number to use with the fg, bg, wait, kill and other shell commands. You must prefix the job number with a percent sign (%).
A plus sign (+) identifies the default or current job.
A minus sign (-) identifies the previous job.
%1
fg %1
kill %2
29379Process ID - An identification unique number that is automatically assigned to each process when it is created on the system.kill 9379
3Runningstate - The state of job:
Running - The job is currently running and has not been suspended by a signal.
Stopped - The job was suspended.
N/A
4xeyes &command - The command that was given to the shell.script &
firefox url&

You can also use ps command to list the processes running on the system:
$ ps

#3: Stop or suspend running jobs

Hit the [Ctrl]-[Z] key or use kill command as follows:

kill -s stop PID

In this example, start ping command and use the Ctrl-Z key sequence to stop the ping command job:

Animated gif 01: Suspending ping command job

Animated gif 01: Suspending ping command job

#4: Resume suspended/stopped job in the foreground

Let us resume or bring stopped ping job to the foreground and make it the current job with the help of fg command. The syntax is as follows:

## Job id number 5 for ping command ##
fg %5

I can also state any job whose command line begins with the string "ping":

## %String ##
fg %ping

Sample outputs:

64 bytes from www.cyberciti.biz (75.126.153.206): icmp_req=3 ttl=53 time=265 ms
64 bytes from www.cyberciti.biz (75.126.153.206): icmp_req=4 ttl=53 time=249 ms
64 bytes from www.cyberciti.biz (75.126.153.206): icmp_req=5 ttl=53 time=267 ms
^C

#5: Resume suspended/stopped job in the background

In this example, I am going to update all installed packages on Red Hat or CentOS Linux production server using yum command background job:
# yum -y update &>/root/patch.log &
However, due to some reason (say load issue) I decided to stop this job for 20 minutes:
# kill -s stop %yum
Sample outputs:

[7]+  Stopped                 yum -y update &>/root/patch.log &

Restart a stopped background yum process with bg

Now, I am going to resume stopped the yum -y update &>/root/patch.log & job, type:
# bg %7
OR
# bg %yum
Sample outputs:

[7]+ yum -y update &>/root/patch.log &

#6: Kill a job / process

To stop/kill a yum command process, enter the following kill command whose jobID was 7:
# kill %7
OR
# kill pid
Sample outputs:

[7]+  Terminated              yum -y update &>/root/patch.log &

On Linux/FreeBSD/OS X Unix you can use killall command to kill process by name instead of PID or jobID.

#7 Why does shell kill off all my background jobs when I logout?

In this example, I am going to start pdfwriter.py job to generate pdf files for this site in bulk:

 
~/scripts/www/pdfwriter.py --profile=faq --type=clean --header=logo\
--footer-left "nixCraft is GIT UL++++ W+++ C++++ M+ e+++ d-" \
--footer-right "Page [of] of [total]" &
 

As soon as I logout from shell, pdfwriter.py job will be killed by my shell. To overcome this problem use disown shell builting command to tell the shell not to send a HUP signal, type:
$ ~/scripts/www/pdfwriter.py --profile=faq .... &
$ disown
$ exit

#8 Prevent job from being killed on logout using an external command called nohup

You can also use nohup command to execute jobs after you exit from a shell prompt:
$ nohup ~/scripts/www/pdfwriter.py --profile=faq .... &
$ exit

#9: Finding the PID of last job

To find the the process ID of the most recently executed background (asynchronous) command, use bash shell special parameter $!
$ gedit foo.txt &
$ echo "PID of most recently executed background job - $!"

Sample outputs:

PID of most recently executed background job - 9421

#10: Wait for job completion

The wait command waits for given process ID or jobID (job specification) , and reports its termination status. The syntax is as follows:

 
/path/to/large-job/command/foo &
wait $!
/path/to/next/job/that-is-dependents/on-foo-command/bar
 

Here is one of my working script:

#!/bin/bash
# A shell script wrapper to create pdf files for our blog/faq section
########################################################################
# init() - Must be run first 
# Purpose - Create index file in $_tmp for all our wordpress databases 
########################################################################
init(){
 _php="/usr/bin/php"
 _phpargs="-d apc.enabled=0"
 _base="~/scripts"
 _tmp="$_base/tmp"
 _what="$1"
 for i in $_what
 do
        [[ ! -d "$_tmp/$i" ]] && /bin/mkdir "$_tmp/$i"
        $_php $_phpargs -f "$_base/php/rawsqlmaster${i}.php" >  "$_tmp/$i/output.txt"
 done
}
 
#####################################################
# Without index file, we can out generate pdf files
#####################################################
init blog
 
###########################################################
# Do not run the rest of the script until init() finished
###########################################################
wait $!
 
## Alright, create pdf files 
~/scripts/www/pdfwriter.py --profile=blog --type=clean --header=logo\
--footer-left "nixCraft is GIT UL++++ W+++ C++++ M+ e+++ d-" \
--footer-right "Page [of] of [total]"
 

Linux and Unix job control command list summary

CommandDescriptionExample(s)
&Put the job in the backgroundcommand &
%nSet the job with the given n (number)command %1
%WordRefer the job whose command line begins with the Wordcommand %yum
%?WordRefer any job whose command line contains the Wordcommand %?ping
%%
%+
Refer to the current jobkill %%
kill %+
%-Refer to the previous jobbg %-
CTRL-Z
kill -s stop jobID
Suspend or stop the jobkill -s stop %ping
jobs
jobs -l
List the active jobsjobs -l
bgPut jobs to the backgroundbg %1
bg %ping
fgPut job to the foregroundfg %2
fg %apt-get

A note about shell built-in and external commands

Run the following type command to find out whether given command is internal or external:

 
type -a fg bg jobs disown
 

Sample outputs:

fg is a shell builtin
fg is /usr/bin/fg
bg is a shell builtin
bg is /usr/bin/bg
jobs is a shell builtin
jobs is /usr/bin/jobs
disown is a shell builtin

In almost all cases, you need to use shell built-in commands. All external commands such as /usr/bin/fg or /usr/bin/jobs works in a different shell environment, and can not use parent shell's environment.

Conclusion

I hope you enjoyed this blog post series (rss feed) and I suggest that you read the following for more information:

I am planning to add more in-depth tutorial in this series. Please let me know if you need to see specific topic in the comment section below.

TwitterFacebookGoogle+PDF versionFound an error/typo on this page? Help us!

  • H4CKN3T

    Very nice article my friend.

  • Leonardo Barros

    It’s great

  • wanderer

    Very useful article. Keep them coming.

  • nbhargav

    It’s wonderful and certainly helps Linux power users and administrators. Keep up the good work. Thanks.

  • miker

    You can also use “disown” to detach an existing job from the shell so that it is not subject to SIGHUP when logging out.

  • Connor McBrine-Ellis

    Awesome tips. Didn’t know about jobs or disown! Thanks.

  • Rikka Muromi

    Great great post !

  • feilong

    Good Tips. Thanks to share.I knew the nohup but not the awesome the “disown my son” ! thx miker too.

  • Peter Tierno

    Very helpful. Thank you.

Previous post:

Next post: