ASPN ActiveState Programmer Network  
ActiveState, a division of Sophos
/ Home / Perl / PHP / Python / Tcl / XSLT /
/ Safari / My ASPN /
Cookbooks | Documentation | Mailing Lists | Modules | News Feeds | Products | User Groups
Submit Recipe
My Recipes

All Recipes
All Cookbooks


View by Category

Title: Running Batch Commands
Submitter: Jordan Callicoat (other recipes)
Last Updated: 2006/07/19
Version no: 1.3
Category:

 

Not Rated yet


Description:

This recipe is a simple (very simple) batch process dispatcher. It allows you to utilize a simple file with a list of commands to run to make your command-line life a little easier. I use it for mencoder so I don't have to type/paste in a bunch of commands for backing up my DVDs. I can just write a batch file. And if there is an error somewhere along the way, or I need to stop for some reason, I can just start where I left off when I am ready.

Source: Text Source

#!/bin/env python
# coding:utf-8
# vim:ts=4:enc=utf-8

"""
Simple batch file processing module

Format of batch file:

    - A # is a comment delimiter, ignore everything on the line.
    - Anything else is command to run - no line continuations!
    
    You can basically just use a list of commands understood
    by the shell.

Example batch file:

    echo "Cmd 1" # this is a comment
    df -h
    # this is a comment too
    ls -lh

    echo "Cmd 4"

Simple, eh?

ver 1.1 - slight cleanup
ver 1.2 - remove interactive jobs (causing some bugs),
          rename variables to be more intuitive, add comments

If you really want to have interactive jobs, you could use
something like this bit of ugliness (but all on one line!):

    read -t 30 -p "Run command? [Y]"; if [ -z ${REPLY} ] || 
    [ ${REPLY} != "N" ]; then echo "I like cheese"; fi

ver 1.3 - minor cleanup
"""

import os
import sys

class SimpleBatchFile:
    """
    This is the main class
    
    Instantiate it then call run()
    """
    def _exec(self, command, jobnum, linenum, batchfile):
        """Execute a command in a subshell, die on errors"""
        print('     Starting job: %s\nExecuting command: %s\n' \
              % (jobnum, command))
        rv = os.system(command)
        if (rv):
            print('Problem running job...\n'
                  'File: %s\n'
                  ' Job: %d\n'
                  'Line: %d\n'
                  '...dieing!' % (batchfile, jobnum, linenum))
            sys.exit(rv)

    def __init__(self, batchfile):
        """Start the fun"""
        if not (os.path.isfile(batchfile)):
            print('Cannot find batch file: %s' % batchfile)
            sys.exit(1)
        self.file = batchfile
        fd        = open(batchfile, 'rb')
        data      = fd.readlines()
        fd.close()
        self.jobs = []
        for i in range(0, len(data)):
            item = data[i].strip()
            ## skip comments and empty lines
            if (item.startswith('#', 0, 1) or item == ''):
                continue
            ## format for jobs is (command, jobnum, linenum)
            self.jobs.append((item, len(self.jobs) + 1, i + 1))
        self.jobcount = len(self.jobs)

    def list(self):
        """List jobs and so forth"""
        for i in range(0, self.jobcount):
            if (i == 0):
                pad = ''
            else:
                pad = '========\n'
            print('%s    Job: %s\n   Line: %s\nCommand: %s' \
                    % (pad,
                       self.jobs[i][1],
                       self.jobs[i][2],
                       self.jobs[i][0]))

    def run(self, start=1, end=None):
        """
        to start from a given job use n, e.g., 3
        or to run a range of jobs use n:n, e.g., 3:5
        or for a single job only use n:n, e.g., 2:2
        no args means all jobs in batch are run
        """
        ## some bounds checking and logics
        if not (end):
            end = self.jobcount
        if (start < 1):
            start = 1
        if (start > self.jobcount):
            start = self.jobcount
        if (end > self.jobcount):
            end = self.jobcount
        if (end <= start):
            end = start
        for i in range(start - 1, end):
            self._exec(self.jobs[i][0],
                       self.jobs[i][1],
                       self.jobs[i][2],
                       self.file)

## end class SimpleBatchFile

if (__name__ == '__main__'):
    ## standalone script
    def get(lst, idx):
        """Return the value of lst[idx] or None"""
        if (len(lst) > idx):
            return lst[idx]
        else:
            return None
    ## get batch file name from argv
    bfnm = get(sys.argv, 1)
    ## no file given, print usage and exit
    if not (bfnm):
        me = os.path.basename(sys.argv[0])
        print('Usage: %s batch_file [start_job_number]' % me)
        sys.exit(1)
    ## instantiate class
    sbf  = SimpleBatchFile(bfnm)
    ## get range from argv
    scmd = get(sys.argv, 2)
    if not (scmd):
        ## run all jobs
        sbf.run()
    elif ('-l' in scmd):
        ## show job list
        sbf.list()
    elif (':' in scmd):
        ## run range of jobs
        scmd, ecmd = scmd.split(':')
        if not (ecmd):
            ecmd = 0
        sbf.run(int(scmd), int(ecmd))
    else:
        ## run all jobs including and after
        sbf.run(int(scmd))

Discussion:

This lets you run a single job (e.g., "1:1"), a range of jobs (e.g., "1:3"), start with one job and then do all jobs after that one (e.g., "7"), or run all jobs from start to finish (no input). Also, passing -l will call the list method and show you each job, the command it runs and what line it appears on in the batch file.

Nota bene: Jobs are indexed from 1, not 0. So if you want to run the second job use "2:2" rather than "1:1". Use -l to see all jobs and ther slots.



Add comment

No comments.



Highest rated recipes:

1. A simple XML-RPC server

2. Web service accessible ...

3. IPy Notify

4. Treat the Win32 Registry ...

5. a friendly mkdir()

6. Wrapping template engine ...

7. Assignment in expression

8. Changing return value ...

9. Implementation of sets ...

10. bag collection class




Privacy Policy | Email Opt-out | Feedback | Syndication
© 2006 ActiveState Software Inc. All rights reserved.