Welcome, guest | Sign In | My Account | Store | Cart
#!/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))

    def __init__(self, batchfile):
        """Start the fun"""
        if not (os.path.isfile(batchfile)):
            print('Cannot find batch file: %s' % batchfile)
        self.file = batchfile
        fd        = open(batchfile, 'rb')
        data      = fd.readlines()
        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 == ''):
            ## 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 = ''
                pad = '========\n'
            print('%s    Job: %s\n   Line: %s\nCommand: %s' \
                    % (pad,

    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):

## 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]
            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)
    ## instantiate class
    sbf  = SimpleBatchFile(bfnm)
    ## get range from argv
    scmd = get(sys.argv, 2)
    if not (scmd):
        ## run all jobs
    elif ('-l' in scmd):
        ## show job list
    elif (':' in scmd):
        ## run range of jobs
        scmd, ecmd = scmd.split(':')
        if not (ecmd):
            ecmd = 0
        sbf.run(int(scmd), int(ecmd))
        ## run all jobs including and after


  • revision 4 (17 years ago)
  • previous revisions are not available