Checking jobs in a shell script.

Posted on 1998-05-04
Last Modified: 2013-12-26
I'm trying to use jobs builtin to see which of the jobs that my shellscript spawned have exited.  But it just doesn't seem to work.  For example, consider the following:

hjstein@blinky:~$ cat jobtest

tail -f ~/.bashrc >/dev/null &
hjstein@blinky:~$ ./jobtest
hjstein@blinky:~$ ps -aux | grep tail
hjstein  21272  1.0  0.4   880   316  ?  S   13:12   0:00 tail -f /home/hjstein
hjstein  21274  0.0  0.5   972   344  ?  S   13:12   0:00 grep tail

The tail is running, but jobs doesn't report anything.  WHY!?!?!?!

Also, how do I get around it?

This is on linux with bash.  zsh behaves the same way.

Question by:hj2

Expert Comment

ID: 1292738
tail is running on your initialisation file which means that it will periodically display the output of that file. jobs is running in a different shell so tail will not display its output.

Author Comment

ID: 1292739
jobs is run by the same shell which ran tail, as is evident by running the same 2 commands by hand:

   hjstein@blinky:~$ tail -f ~/.bashrc >/dev/null & 
   [1] 433
   hjstein@blinky:~$ jobs
   [1]+  Running                 tail -f ~/.bashrc >/dev/null &

This is also evident by sourcing jobtest instead of running it:

   hjstein@blinky:~$ . jobtest
   [1]+  Running                 tail -f ~/.bashrc >/dev/null &
   hjstein@blinky:~$ . jobtest
   [1]-  Running                 tail -f ~/.bashrc >/dev/null &
   [2]+  Running                 tail -f ~/.bashrc >/dev/null &
   hjstein@blinky:~$ . jobtest
   [1]   Running                 tail -f ~/.bashrc >/dev/null &
   [2]-  Running                 tail -f ~/.bashrc >/dev/null &
   [3]+  Running                 tail -f ~/.bashrc >/dev/null &

The only difference btw ". jobtest" and "./jobtest" is that the former is run by the current shell, and the latter is run in a subshell.

LVL 51

Expert Comment

ID: 1292740
The reason is that in bash scripts background jobs are childs
of init (PID = 1), while in an interactive bash they are a child
of the bash itself. So the jobs command cannot find them because
they are in a different program group.
See man bash for a rough description about JOB CONTROL, for more
details I think you have to step deeper into the sources of bash.

Your script will work with csh (and probably with tcsh also).
Gigs: Get Your Project Delivered by an Expert

Select from freelancers specializing in everything from database administration to programming, who have proven themselves as experts in their field. Hire the best, collaborate easily, pay securely and get projects done right.


Author Comment

ID: 1292741
ahoffmann writes:

   The reason is that in bash scripts background jobs are childs
   of init (PID = 1), while in an interactive bash they are a
   child of the bash itself.

Why is this?  I didn't notice any mention of this in the man page.  Do you have any reference for this (other than the source code)?


Author Comment

ID: 1292742
I confirmed your answer with ps -l, so I'm ready to give you (ahoffmann) an A rating, but I'd still like to know:

a) why processes spawned by noninteractive shells are children of init instead of being children of the shell that spawned them, and

b) Is there any way around this under bourne shells (bash, sh, ksh, ...)?

If you don't know, then just say so, and I'll close the question.
LVL 51

Accepted Solution

ahoffmann earned 200 total points
ID: 1292743
As I said, please refer to man bash for the "program group"
That there is a difference for script and interactive, I also
found by testing ;-) so that's the reason I said you must look
at the sources for the hard details.

Why it is different for bash and sh? I don't know. But bash and
sh behave the same (ksh probably too) 'cause sh is the ancestor
of all those shells, while csh was a complete new approach.

Author Comment

ID: 1292744
Ok.  I'm satisifed.  I finally found "set -m" in the man page, which infers that job control is on by default for interactive shells and off otherwise.  The section on job control infers that subprocesses will be children of the current shell when job control is on and will be children of init when job control is off.

Thanks for your help.


Expert Comment

ID: 1292745
I am just curious here.  But on my host, HPUX10.10, both ksh and sh do not behave that way.  The background jobs are not owned by init, they are owned by the shell.  Here is what I get:

/user3/seedy/tmp> echo $0

/user3/seedy/tmp> cat ./jobtst
tail -f ~/.kshrc >/dev/null &
ps -l -u seedy
jobs  -l

/user3/seedy/tmp> ./jobtst
  1 R  1026 15225 15072  0 178 20  18d1980  108        - ttyp4     0:00 sh
  1 R  1026 15227 15225  3 178 20  175ba80   23        - ttyp4     0:00 ps
  1 S  1026 15226 15225  2 168 20  203c480    8 7ffe6000 ttyp4     0:00 tail
  1 S  1026 15072 14999  0 158 20  17ad980  107   b687c0 ttyp4     0:00 sh
[1] + 15226      Running                 <job name not known>

As you can see tail's ppid is not 1.  Ksh also behaves this way.

hj2, if you do a ps -l outside the jobtst script, the tail will
be owned by pid 1 - this because the shell that was executing jobtst has terminated and hence the tail process is inherited by init.

Author Comment

ID: 1292746
Good observation.  I don't understand this process group business enough to figure out what's going on...

LVL 51

Expert Comment

ID: 1292747
Seedy, you're right: processes spawned by a shell get PID 1 if
their parrent dies.

hj2,  set -m   explains the things about the process groups
So my answer was right half the way, thanks for the points anyway

Featured Post

Courses: Start Training Online With Pros, Today

Brush up on the basics or master the advanced techniques required to earn essential industry certifications, with Courses. Enroll in a course and start learning today. Training topics range from Android App Dev to the Xen Virtualization Platform.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
Process filename extension 3 184
dog bark java program 15 95
Use of condition with 'serial' in ansible 2 58
Making an alias 7 94
Introduction: Hints for the grid button.  Nested classes, templated collections.  Squash that darned bug! Continuing from the sixth article about sudoku.   Open the project in visual studio. First we will finish with the SUD_SETVALUE messa…
Introduction: The undo support, implementing a stack. Continuing from the eigth article about sudoku.   We need a mechanism to keep track of the digits entered so as to implement an undo mechanism.  This should be a ‘Last In First Out’ collec…
This video will show you how to get GIT to work in Eclipse.   It will walk you through how to install the EGit plugin in eclipse and how to checkout an existing repository.
This Micro Tutorial demonstrates using Microsoft Excel pivot tables, how to reverse engineer competitors' marketing strategies through backlinks.

776 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question