views:

702

answers:

7

I need to run a process, wait a few hours, kill it, and start it again. Is there an easy way that I can accomplish this with Python or Bash? I can run it in the background but how do I identify it to use kill on it?

A: 

One idea: Save the process's PID (returned by fork() in your child process) to a file, then either schedule a cron job to kill it or kill it manually, reading the PID from the file.

Another option: Create a shell script wrapper that automatically kills and restarts the process. Same as above, but you can keep the PID in memory, sleep for as long as you need, kill the process, then loop.

lc
A: 

Take a look at the start-stop-daemon utility.

innaM
The link's broken.
lc
...I fixed it to one that works, but you should check it's the right page you wanted.
lc
Yep, that's the one. Sorry.
innaM
A: 

You could always write a script to search for those processes and kill them if found. Then add a cronjob to execute the script.

Find process ID of a process with known name

Kill processes with a known ID

In python os.kill() can be used to kill a process given the id.

monkut
+3  A: 

This is in Perl, but you should be able to translate it to Python.

#!/usr/bin/perl

use strict;
use warnings;

#set times to 0 for infinite times
my ($times, $wait, $program, @args) = @ARGV;

$times = -1 unless $times;
while ($times--) {
    $times = -1 if $times < 0; #catch -2 and turn it back into -1
    die "could not fork" unless defined(my $pid = fork);

    #replace child with the program we want to launch
    unless ($pid) {
        exec $program, @args;
    }

    #parent waits and kills the child if it isn't done yet
    sleep $wait;

    kill $pid;
    waitpid $pid, 0; #clean up child
}

Because I am trying to teach myself Python, here it is in Python (I do not trust this code):

#!/usr/bin/python

import os
import sys
import time

times    = int(sys.argv[1])
wait     = int(sys.argv[2])
program  = sys.argv[3]
args     = []
if len(sys.argv) >= 4:
    args = sys.argv[3:]

if times == 0:
    times = -1

while times:
    times = times - 1
    if times < 0:
     times = -1

    pid = os.fork()

    if not pid:
     os.execvp(program, args)

    time.sleep(wait)

    os.kill(pid, 15)
    os.waitpid(pid, 0)
Chas. Owens
The process id can't be used by another process because the child has not been reaped by the parent yet (it is a zombie).
Chas. Owens
+3  A: 

With bash:

while true ; do
    run_proc &
    PID=$!
    sleep 3600
    kill $PID
    sleep 30
done

The $! bash variable expands to the PID of the most recently started background process. The sleep just waits an hour, then the kill shuts down that process.

The while loop just keeps doing it over and over.

paxdiablo
Does bash autoreap its children? This will either leave a bunch of zombies (if bash doesn't autoreap) or you run the risk of sending SIGTERM to an unrelated process (bash autoreaps, freeing up the pid for another process).
Chas. Owens
I'm assuming the process doesn't exit (based on the question), in which case the PID won't be re-used before it's killed.
paxdiablo
The process does exit but it is a really long running one. This solution works great!
hekevintran
A: 

In python:

import subprocess
import time

while True:    
    p = subprocess.Popen(['/path/to/program', 'param1', 'param2'])
    time.sleep(2 * 60 * 60) # wait time in seconds - 2 hours
    p.kill()

p.kill() is python >= 2.6.

On python <= 2.5 you can use this instead:

os.kill(p.pid, signal.SIGTERM)
nosklo
I get NameError: name 'subprocess' is not defined
Chas. Owens
Adding import subprocess results in AttributeError: 'Popen' object has no attribute 'kill'
Chas. Owens
@chas. owens: p.kill() is for python >= 2.6.
nosklo
A: 

Not an ideal method but if you know the name of the program and you know it's the only process of that name running on the system you can use this in cron:

0 */2 * * * kill `ps -ax | grep programName | grep -v grep | awk '{ print $1 }'` && ./scriptToStartProcess

This will run every two hours on the hour and kill programName then start the process again.

Garry Harthill