# Python command shell utility # # simplifies debugging, editing, etc; # augments normal Python commmand line; # cmd history: redundant if readline built; # # use: python psh.py # python; import psh; psh.go(); help # # TODO: # - cmd history scrolling via arrow keys # - arbitrary '$' aliases/replacements # - make it a class, so can use in other # apps (call self.handler, not python()) # - see about using pdb's command class # so shell cmds recognized while in pdb # - allow for multi-line statements- # start == keyword and last == ':', {, ... ############################################# from os import * from string import * editor = 'edit' # 'vi' memory = 20 # settable: % shell.editor = 'vi' histnum = 0 # retain all settings for next go() history = [] prompter = '%' aliases = [] def interact(): while 1: cmd = raw_input(prompter + ' ') cmd = prescan(cmd) if cmd == 'quit': break execute(cmd) def execute(cmd): global history, histnum args = split(cmd) if not args: # empty line or all blanks return # else >= 1 word on line if shell_command(args[0]): func = eval(args[0]) # get function for command try: func(args[1:]) # null if no args[1:] except: print 'bad shell command' # any errors come here else: try: python(cmd) # try as python command except: print 'bad command:', args[0] if args[0] != 're': histnum = histnum+1 history = history[-(memory-1):] + [(histnum, cmd)] ################################################## # command for python or psh? check first word ################################################## def shell_command(name): return (name in help_dir.keys()) def python(cmd): import __main__ exec(cmd, __main__.__dict__, __main__.__dict__) ##################################################### # one function per keyword command; add to help too ##################################################### def quit(args): raise NameError # superfluous args def prompt(args): global prompter prompter = args[0] def pwd(args): print getcwd() def cd(args): if not args: chdir() else: chdir(args[0]) print getcwd() def ls(args): if not args: system('ls') # listdir('.') else: system('ls ' + args[0]) # listdir(args[0]) def ed(args): system(editor + ' ' + args[0]) def os(args): system(join(args)) # ex: os cp shell.py a: # 'os' alone starts shell def fix(args): import sys # ex: fix holmes module = args[0] ed([module + '.py']) # assumes in cwd/'.' if module in sys.modules.keys(): python('reload(' + module + ')') # reload in __main__ else: python('import ' + module) # first load in __main__ def db(args): import pdb pdb.run(join(args)) # ex: db shell.help(['ls']) # pdb runs cmd in __main__ def hi(args): for (number, command) in history: print number, '=>', command def re(args): if not args: repeat = history[len(history)-1][1] else: try: number = eval(args[0]) # fail if non-num for (num, cmd) in history: if num == number: repeat = cmd; break else: raise NameError # number not found except: prefix = join(args) history.reverse() for (num, cmd) in history: if cmd[:len(prefix)] == prefix: repeat = cmd history.reverse() break else: history.reverse() print 'bad history command number' return print 'redo:', repeat execute(repeat) # recursive call def src(args): # import sys # save = (sys.stdin, sys.stdout) file = open(args[0], 'r') # open can fail while 1: cmd = file.readline() # read can fail if not cmd: break cmd = prescan(cmd) if cmd == 'quit': break if cmd: print '[' + cmd + ']...' execute(cmd) file.close() def equ(args): if not args: for (patt, subst) in aliases: print `patt`, '=>', `subst + ' '` else: global aliases # (from, to) aliases = [(args[0], join(args[1:]))] + aliases # to can be a list ########################################################## # currently only allows aliase name to be at the front # of the command line, not embedded in it (no '$' subst); # cmd pattern must be followed by a blank iff the patt # is not a special char, and the cmd contains args; # this stops 'quit' from becoming 'quit uit' when 'q' # has been aliased to 'quit'; ########################################################## def prefix(cmd, patt): if cmd[:len(patt)] == patt: if patt[0] not in letters: return 1 if len(cmd) == len(patt): return 1 if cmd[len(patt)] in whitespace: return 1 return 0 def prescan(cmd): cmd = strip(cmd) # strip blanks for 'quit' test if cmd and cmd[0] == '#': # allow comments in src files return '' for (patt, subst) in aliases: if prefix(cmd, patt): cmd = strip(subst + ' ' + cmd[len(patt):]) # allow '!' for 're ' print 'equ:', cmd # alloq 'q' for quit break return cmd ################################################## # help_dir also serves to identify shell # command names (distinct from python cmds); ################################################## help_dir = { 'pwd': ('', 'print current directory'), 'ls': ('