[net.sources] csh-script to run a job after an existing job terminates

peters@cubsvax.UUCP (Peter S. Shenkin) (07/22/86)

DESCRIPTION:
after:	a procedure that waits until a particular running process terminates, 
	then initiates a new process.  This runs under csh, but should be
	easily translatable to bsh or ksh.

USAGE:
after pid shellscript [seconds]

"pid" is the pid number of a running job.
"shellscript" is the name of an executable file which contains commands to be 
	executed once the process number "pid" has terminated.
"seconds" is an optional integer which specifies how often "after" will test for
	termination of process number "pid".  If not specified, 900 seconds 
	(i.e., every 15 minutes) is the default.

MOTIVATION:
	I often run very long, cpu-intensive jobs on our VAX 11/780, which runs
ULTRIX.  If I have two of these jobs running simultaneously, they generally take
considerably longer to complete than if they run sequentially, even if I'm
the only one on the machine.  In addition, if they run sequentially, I get to 
see the results of the first long before the second terminates.  If I know in 
advance I'm going to run two in a row, I can execute a script that runs them in 
order, or else enter the two jobs on a line separated by a semi-colon.  
Sometimes, however, I don't decide to run job2 until job1 has already started;
also, setting up such a job sometimes takes a good deal of preparation, and
I'd like to start job1, then turn my attention to preparing the input for job2,
then tell job2 to start after job1 finishes, then go home.

INSTALLATION:
	Install the first file, "after", in your ~/bin, and the second file,
"awkfinafter", in your ~/etc.  If you don't like these directories, pick ones
you do; if you change the directory for awkfinafter, you'll have to change
the assignment of awkfin in "after" to correspond.

PHILOSOPHICAL RUMINATIONS:
	This script seems too simple to post, yet too useful not to.
	The way it works is to create an awk program file using sed to insert
the process id supplied to after.  Then the output of ps is awk-ed, and if the
process id is not found, the shellscript given to after is executed.  If it is
found, after "sleep"s for the time interval given (or for a default time of
15 minutes) before trying again.  (It might sound simpler to search the output
of ps using "fgrep pid", but ps will return a line for the fgrep job, so the 
search will always succeed!)
	Note that "after" will not terminate until the script it runs
terminates;  that means that if you've used "after" to queue up job2 to run 
after job1 terminates, you can use the pid of that "after" to run a second 
"after" which queues up job3, and rest assured that job3 will not commence until
job2 terminates.  And so on ad infinitum (or at least ad nauseum).
	Enjoy!  If you like it a lot or think it's dumb or something drop me a
line.

Peter S. Shenkin	 Columbia Univ. Biology Dept., NY, NY  10027
{philabs,rna}!cubsvax!peters		cubsvax!peters@columbia.ARPA

----------------------file $home/bin/after begins here--------------------------
#
# "after". 21jul86. runs a shell script after a running process has finished
# Peter S. Shenkin	 Columbia Univ. Biology Dept., NY, NY  10027
# {philabs,rna}!cubsvax!peters		cubsvax!peters@columbia.ARPA

# parse command line, and set sleep interval if not specified
if( $#argv == 3 ) then
	set seconds=$3
else if( $#argv == 2 ) then
	set seconds=900
else
	echo 'usage: after pid shellscript [seconds, default=900 ]'
	exit
endif

# initialize internal variables
set awkfin=$home/etc/awkfinafter
set awkfout=/tmp/after$$

# create awk program file
sed -e s/@@/$1/ $awkfin> $awkfout

# take a breather for $seconds;  check for pid;
#   when no longer found, run script ($2), cleanup and exit
while 1
	sleep $seconds
	if( 0 == `ps | awk -f $awkfout` ) then
		$2
		/bin/rm $awkfout
		exit
	endif
end
----------------------file $home/bin/after ends here--------------------------
----------------------file $home/etc/awkfinafter starts here------------------
BEGIN		{ found = 0 }
$1 == @@	{ found = 1; exit }
END		{ print found }
----------------------file $home/etc/awkfinafter ends here------------------

stan@amc.UUCP (Stan Tazuma) (07/25/86)

In article <515@cubsvax.UUCP> peters@cubsvax.UUCP (Peter S. Shenkin) writes:
>
>DESCRIPTION:
>after:	a procedure that waits until a particular running process terminates, 
>	then initiates a new process.  This runs under csh, but should be
>	easily translatable to bsh or ksh.
>
I think it's a useful tool, but there are simpler ways to do it (at
least under a BSD Unix (which includes the Ultrix you're using)).
Here's a program I came up with a while back.  It's called waitp.
It has the same args. as "after".
------------waitp.c------------
/* this program will wait until a given process dies
 *  e.g.   waitp  10309  10
 *
 * 3/12/85 - skt
 */
#include <stdio.h>

#define DEFAULT_PAUSE		30

extern errno;

main(argc,argv)
int argc;
char **argv;
{
    char *cmdname = argv[0];
    int pid;
    register ret;
    register sleep_time = (argc > 2) ? atoi(argv[2]) : DEFAULT_PAUSE ;

    if (argc == 1) {
	fprintf(stderr, "usage:  %s  pid  [ pause-time ]\n", cmdname);
	exit(1);
    }
    pid = atoi(argv[1]);
    while ((ret = getpgrp(pid)) >= 0)
	if (sleep_time > 0) sleep(sleep_time);

    /* getpgrp returns -1 when the process goes away, and
     * sets errno == 3 (ESRCH in /usr/include/errno.h)
     */
    /* printf("getpgrp returned %d\n", ret); */
    /* printf("errno is %d\n", errno); */

    exit(0);
}
-----------------
The way to use this is as follows.  Suppose you start a job in the
background.  Then you want to run another job after that one completes.
First do a "jobs" to find out the pid of the first job; let's suppose
the pid is 12345.  Then run the job:

	waitp 12345; <arbitrary command> &

--------------
If you want to do it as a shell script, the ps command can be used
to look at an arbitrary process, by pid.  E.g.,
--------------(first, in csh since your script was in csh)
#! /bin/csh -f
set pid = $1
if ($#argv == 2) then
    set sleep_time = $2
else
    set sleep_time = 30
endif
while (1)
    if ( { ps \#$pid } ) then >/dev/null
	sleep $sleep_time
    else
	exit 0
    endif
end
--------------(here, in sh since sh probably has less impact on the system)
#! /bin/sh
pid=$1
sleep_time=${2-30}
while :
do
    if ps \#$pid >/dev/null
    then
	sleep $sleep_time
    else
	exit 0
    fi
done
---------------
For AT&T Unix versions, getpgrp() doesn't behave in the above way (waitp.c).
The AT&T ps command can be used to look at a specific process, though
using a different ps argument than above.

Stan Tazuma
Applied Microsystems Corp.
	...uw-beaver!tikal!amc!stan