|
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
"""
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()
if (item.startswith('#', 0, 1) or item == ''):
continue
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
"""
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)
if (__name__ == '__main__'):
def get(lst, idx):
"""Return the value of lst[idx] or None"""
if (len(lst) > idx):
return lst[idx]
else:
return None
bfnm = get(sys.argv, 1)
if not (bfnm):
me = os.path.basename(sys.argv[0])
print('Usage: %s batch_file [start_job_number]' % me)
sys.exit(1)
sbf = SimpleBatchFile(bfnm)
scmd = get(sys.argv, 2)
if not (scmd):
sbf.run()
elif ('-l' in scmd):
sbf.list()
elif (':' in scmd):
scmd, ecmd = scmd.split(':')
if not (ecmd):
ecmd = 0
sbf.run(int(scmd), int(ecmd))
else:
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.
|