This program extracts, expands and executes a command stored in an arbitrary file usually the primary file. This is similar to the #! facility in UNIX.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 | #!Test c:\bin\messagebox.exe Display for {a} %xyz% {} {xyz} {} and {p}
## #!Test2 c:\bin\messagebox.exe Display for {a} and {} with {} and {p}
#!Edit {o}\qeditor.exe {a} !!
# Run the #!Inst command
#! c:\bin\qeditor.exe "{a}" !!
#!py c:\bin\messagebox.exe "{a}" is a python program
#!Inst c:\windows\system32\cmd.exe /C copy "{a}" "{i}\{f}" !!
#!BadI c:\windows\system32\cmd.exe /C copy "{a}" "{i}\{f}"
#!Run c:\sys\python27\pythonw.exe "{a}" list of arguments
## #!OKI c:\windows\system32\cmd.exe /C copy "{a}" "{t}\{f}" !!
#!pynew c:\bin\messagebox.exe Display for {a} new
#!oldpy c:\bin\messagebox.exe Display for "{a}" old
mHelpText = '''
# ----------------------------------------------
# Name: pb
# Description: Expand and execute command from file
## D20H-57 Expand and execute command
#
# Author: Philip S. Rist
# Date: 10/26/2010
# Copyright 2010 by St. Thomas Software
# ----------------------------------------------
# This program is freeware. It may be used
# for any moral purpose. You use it at your
# own risk. St. Thomas Software makes no
# guarantees to its fitness to do anything.
#
# If you feel you must pay for it. Please
# send one million dollars to
#
# The International Rescue Committee
# 122 East 42nd Street
# New York, N.Y. 10168-1289
#
# Ok, we are in a recession. So, make it a half
# million.
# pb.py -
# Scan file for specified #! keyword then expand and execute command following on line.
# See above for examples. Scanned lines must be at the beginning of the file with no
# blank or shorx t lines preceeding them.
#
# Usage examples:
#
#[HKEY_CLASSES_ROOT\*\Shell\Runpb]
#@="Run"
#"EditFlags"=hex:01,00,00,00
#[HKEY_CLASSES_ROOT\*\Shell\Runpb\Command]
#@="c:\\sys\\python25\\pythonw.exe c:\\bin\\pb.py \"%1\" #!run "
#
# Syntax:
# pb.py [ Options ] <File path> #!<Key> [ <Optional parameter> ... ]
#
# Options:
#
# -c <Count> - Set last line to search for #! default 10
# A too short line will also abort scan
# -d <Directory path> - Set current directory
# -e <Name>=<Value> - Set environment variable
# -h - Display this text
# -s <File to search> - Set name of file containing command, defaults to
# primary file named in <File path>
# -v - Run in verbose mode
# -w <Count> - Set last column in line to search for #! default 15
# -x - Do not run, list expanded command
'''
import sys
import os
import getopt
import Do # Recipe: 577439
import Do2 # Recipe: 577440
import subprocess
def FindCommand(pKey, pFilePath, pSearchPath, pCount=10, pDefault='#!', pList=False, pWidth=10, pVerbose=False):
'''
Find command keyword and extract containing line
pKey -- String identifying line to use as command template
pFilePath -- File to use in macro expansion
pSearchPath -- File to scan for command '
pCount -- Number of lines at the start of the file to scan
pDefault -- Prefix for keys, from UNIX #!
pList -- True to display available commands
pWidth -- Number of columns at start of line in which key must appear
'''
lShortest = 6 # A line shorter than this will abort scan
if not os.path.exists(pSearchPath):
lCommand = ''
print 'pb.py Could not find search file', pSearchPath
else:
# ---- Check allowed key values
if pKey == '' or pKey == pDefault: # #!
lKey = pDefault
elif pKey.find('{') >= 0: # #!{e}
lKey = pDefault + Do.Expand(pKey, pFilePath)
if not lKey.startswith(pDefault):
lKey = pDefault + lKey
elif pKey.startswith(pDefault): # #!text
lKey = pKey
else:
lKey = pDefault + pKey # text
lKey = lKey.lower()
# lKey += ' ' # Full key only
# ---- read maximum scan lines
lFile = open(pSearchPath, 'r')
lText = lFile.readlines(pCount)
lText = lText[0:pCount] #???
lFile.close()
lCommand = ''
# ---- list available commands
if pList:
lText = [x for x in lText if x.find(pDefault) >= 0 ]
lText = [x for x in lText if x.find(pDefault) < pWidth ]
print 'Available Commands in', pSearchPath
for (lCount, lLine) in enumerate(lText):
lLine = lLine.strip()
print "%5d: %s" % (lCount, lLine)
# ---- Scan for selected command
# Since comments in some languages do not start with first character of key,
# the key need not appear at start of line but must appear within first pWidth
# columns to allow for skipping lines with key that are not to be matched
else:
lCount = 0
for lLine in lText:
if len(lLine.strip()) < lShortest: # blank or short line will stop scan
break
lLine = lLine.lower()
lPos = lLine.find(lKey.lower())
if pVerbose:
lCount += 1
print "pb.py %5d: %s" % (lCount, lLine),
if lPos >= 0:
lAt = lPos + 13
print ' ' * lAt + '^'
if lPos >= 0 and lPos < pWidth:
# ---- Full key only
# lCommand = lLine[lPos+len(lKey):]
# ---- Partial keys allowed
lCommand = lLine[lPos+len(lKey):]
if lCommand[0] == ' ': # matched full key
lCommand = lCommand.lstrip()
else:
lPos = lCommand.find(' ') # matched partial key
lCommand = lCommand[lPos:].lstrip()
break
return lCommand[0:-1]
def Expand(pArgs, pFilePath, pSearchPath, pCount, pSep='!!', pDefault='#!', pList=False, pWidth=15, pVerbose=False):
'''
Extract command from file and replace all macros
pArgs -- Args passed to program except file path
#!key and any arguments
pFilePath -- File to use in macro expansion
pSearchPath -- File to scan for command '
pCount -- Number of lines at the start of the file to scan
pSep -- String used to identify end of command, extra arguments will not be appended
pList -- True to display available commands
pWidth -- Number of columns to scan for #!
'''
# ---- Find command
if len(pArgs[1]) == 0:
lKey = pDefault
lStart = 1
elif pArgs[1].startswith(pDefault):
lKey = pArgs[1]
lStart = 2
else:
lKey = pDefault
lStart = 1
lCommand = FindCommand(lKey, pFilePath, pSearchPath, pCount, pDefault=pDefault, pList=pList, pWidth=pWidth, pVerbose=pVerbose)
if lCommand == '':
print 'pb.py Command', lKey, 'not found'
# ---- Expand and insert/append any passed arguments
# Arguments on original pb.py command line will replace {} from left to right
# otherwise they will be appended to the end of the command
if len(lCommand) > 0:
if len(pArgs) > lStart:
for lArg in pArgs[lStart:]:
if lArg.find('{') >= 0:
lArg = Do2.ExpandArg(lArg, pFilePath, '')
lPos = lCommand.find('{}')
if lPos >= 0:
lCommand = lCommand[0:lPos] + lArg + lCommand[lPos+2:]
else:
lCommand += ' ' + lArg
# ---- Prevent unwanted arguments appended to command
lPos = lCommand.rfind(pSep)
if lPos > 0:
lCommand = lCommand[0:lPos]
# ---- Expand all remaining macros
if lCommand.find('{') >= 0:
lCommand = Do.Expand(lCommand, pFilePath)
return lCommand
def submitnow(pArgs, pFilePath, pSearchPath, pCount, pList=False, pExtract=False, pVerbose=False, pWidth=15):
'Expand and submit command'
if pVerbose:
print 'pb.py File path: ', pFilePath
print 'pb.py Search path:', pSearchPath
print 'pb.py Arguments: ', pArgs
lCommand = Expand(pArgs, pFilePath, pSearchPath, pCount, pList=pList, pWidth=pWidth, pVerbose=pVerbose)
# ---- Any macro not expanded will be assumed to be an environment variable
# If %...% had been used it would have been replaced when pb.py was run
lCommand = lCommand.replace('{}',' ') # <-- may want to do something else
lCommand = lCommand.replace('{', '%')
lCommand = lCommand.replace('}', '%')
# ---- Complete execution
if pList: # List only
pass
elif len(lCommand) == 0: # Expansion failed
print 'pb.py Expansion failed'
elif pExtract: # Expand command only
print lCommand
else: # Submit command
lCommand = '"' + lCommand + '"'
if pVerbose:
print 'pb.py Submitting: ', lCommand
subprocess.Popen(lCommand, shell=True)
def setenviron(pValue, pFileName):
'Set environment variable'
lParts = pValue.split('=')
if len(lParts) > 1:
lKey = lParts[0]
lValue = lParts[1]
if lValue.find('{') >= 0:
lValue = Do2.ExpandArg(lValue, pFileName, '')
os.environ[lKey] = lValue
else:
os.environ[pValue] = ''
#sys.argv.extend( [ 'c:\\source\\python\\projects\\program execution\\pb.py', '#!Inst', 'A', '{p}' ] )
#sys.argv.extend( [ 'c:\\source\\python\\projects\\program execution\\pb.py', '#!BadI', 'A', '{p}' ] )
#sys.argv.extend( [ 'c:\\source\\python\\projects\\program execution\\pb.py', '#!OKI', 'A', '{p}' ] )
#sys.argv.extend( [ 'c:\\source\\python\\projects\\program execution\\pb.py', '#!Edit', 'A', '{p}' ] )
if __name__ == '__main__':
(mOptions, mArgs) = getopt.getopt(sys.argv[1:], 'c:d:e:hls:vx')
if len(mArgs) > 1:
# ---- Set defaults
mFilePath = os.path.abspath(mArgs[0])
mArgs[1] = mArgs[1].replace('_', ' ')
mSearchPath = mFilePath
mCount = 10
mList = False
mExtract = False
mVerbose = False
mWidth = 15
mHelp = False
# ---- Scan option list
for (mKey, mValue) in mOptions:
if mKey == '-d': # Set current directory
if mValue.find('{') >= 0:
mValue = Do.Expand(mValue, mFilePath)
os.chdir(mValue)
elif mKey == '-e': # Set environment variable
setenviron(mValue, mFilePath)
elif mKey == '-c': # Set last line to search for #!
try:
mCount = int(mValue)
except Exception, e:
mCount = 10
elif mKey == '-s': # Set search path
mSearchPath = mValue
if mValue.find('{') >= 0:
mSearchPath = Do2.ExpandArg(mSearchPath, mFilePath, '')
if mSearchPath[0] == '"':
mSearchPath = mSearchPath[1:-1]
mSearchPath = os.path.abspath(mSearchPath)
elif mKey == '-h': # Display help only
mHelp = True
elif mKey == '-l': # Display available commands
mList = True
elif mKey == '-x': # List expanded command only
mExtract = True
elif mKey == '-v': # Run in verbose mode
mVerbose = True
elif mKey == '-w': # Set last column in file to search for #!
try:
mWidth = int(mValue)
except Exception, e:
mWidth = 10
if mHelp:
print mHelpText
print 'pb.py Search file:', mSearchPath
print 'pb.py Width: ', mWidth
print 'pb.py Lines: ', mCount
mList = True
else:
submitnow(mArgs, mFilePath, mSearchPath, mCount, mList, mExtract, mVerbose, mWidth)
else:
print 'pb.py Command and/or file path missing'
|
This program scans the head of an arbitrary file looking for a line containing a specified key, such as #!test. When found the command is expanded using the primary path and arguments from the command line and executed. The command 'pb.py mybest.py #!test1' will scan mybest.py for a line containing #!test1. When found it will be expanded and executed. An example set of commands can be found at the top of the program.
Two similar programs are DoCommand, recipe 577441 and DoM recipe 577453 which extract commands from the Windows registry and from a QEditor style menu file.