def __init__(self): # Hiding away BashParser from a wildcard import of shpy # Let's keep those globals tidy! from bash_alike import BashParser self.available_cmds = {"quit": self.f_exit, "logout": self.f_exit, "exit": self.f_exit, "help": self.f_help, "h": self.f_help, "?": self.f_help, "cd": self.f_cd, "pwd": self.f_pwd, "mv": self.f_mv, "cp": self.f_cp, "rm": self.f_rm, "ls": self.f_ls, "dir": self.f_ls, "cat": self.f_cat, "get": self.f_get, "curl": self.f_get, "wget": self.f_get, "mkdir": self.f_mkdir, "untar": self.f_untar, "unzip": self.f_unzip, "vars": self.f_vars, "webdav": self.f_webdav, "pypi": self.f_pypi, "pypi-search": self.f_pypi_search, "pypi-vers": self.f_pypi_vers, "pypi-install": self.f_pypi_install, "selfupdate": self.f_selfupdate} self.hmsg = "Available commands:\n" + \ "-------------------\n" + \ "help - Shows help (also: h, ?)\n" + \ "exit - Quits shpy (also: logout, quit)\n" + \ "pwd - Show current directory\n" + \ "ls [file ..] - List file(s)\n" + \ "cd [dir] - Change directory\n" + \ "mkdir dir - Create directory\n" + \ "cat file - Print file to screen\n" + \ "unzip file.zip [destdir] - Unzip file\n" + \ "untar file.tar [destdir] - Untar file\n" + \ "rm file [..] - Delete files and dirs\n" + \ "mv src [..] dest - Move file(s)\n" + \ "cp src [..] dest - Copy file(s)\n" + \ "get URL [file] - Download file\n" + \ "selfupdate - Update shpy\n" + \ "pypi - Show available PyPI commands\n" + \ "webdav - Run a webdav server in cwd\n" + \ "vars - List variables and values" self.bp = BashParser() try: dir = [x for x in sys.path if ('Python for iOS.app' in x)][0].split('Python for iOS.app')[0] if (dir.startswith('/var')): dir = '/private' + dir except: dir = '/' documents = dir + 'Documents' modules = documents + '/Modules' scripts = documents + '/User Scripts' if (os.getcwd() == '/'): # Chances are we're being run without _rp os.chdir(scripts) env_vars = {'$HOME': documents, '$SCRIPTS': scripts, '$MODULES': modules} self.bp.env_vars = env_vars
class _Shpy: def split_leading_dir(self, path): path = str(path) path = path.lstrip('/').lstrip('\\') if '/' in path and (('\\' in path and path.find('/') < path.find('\\')) or '\\' not in path): return path.split('/', 1) elif '\\' in path: return path.split('\\', 1) else: return path, '' def has_leading_dir(self, paths): common_prefix = None for path in paths: prefix, rest = self.split_leading_dir(path) if not prefix: return False elif common_prefix is None: common_prefix = prefix elif prefix != common_prefix: return False return True def sizeof_fmt(self, num): for x in ['bytes','KB','MB','GB']: if num < 1024.0: if (x == 'bytes'): return "%s %s" % (num, x) else: return "%3.1f %s" % (num, x) num /= 1024.0 return "%3.1f%s" % (num, 'TB') def f_help(self, argv): print self.hmsg def f_ls(self, argv): files = argv[1:] if (not files): files = ['.'] files_for_path = dict() for file in files: full_file = os.path.abspath(file).rstrip('/') file_name = os.path.basename(full_file) dir_name = os.path.dirname(full_file).rstrip('/') if (not os.path.exists(full_file)): print "! Error: Skipped, missing -", self.pretty_path(file) continue if (os.path.isdir(full_file)): # Need to add this as a key and all the files contained inside it _dirs = files_for_path.get(full_file, set()) for new_file in os.listdir(full_file): _dirs.add(full_file.rstrip('/') + '/' + new_file.rstrip('/')) files_for_path[full_file] = _dirs else: _dirs = files_for_path.get(dir_name, set()) _dirs.add(full_file) files_for_path[dir_name] = _dirs # Iterate over the paths, in alphabetical order: paths = sorted(files_for_path.keys()) cwd = os.getcwd().rstrip('/') in_cwd = False if (cwd in paths): # Move cwd to the front, mark that it's present paths.remove(cwd) paths = [cwd] + paths in_cwd = True for i,path in enumerate(paths): if (i > 0): print "\n" + self.pretty_path(path) + "/:" elif (not in_cwd): print self.pretty_path(path) + "/:" for file in sorted(list(files_for_path[path])): full_file = os.path.abspath(file).rstrip('/') file_name = os.path.basename(full_file) if (os.path.isdir(full_file)): print file_name + "/" else: print file_name + (" (%s)" % (self.sizeof_fmt(os.stat(full_file).st_size))) def f_cd(self, argv): target = (argv[1:2] or ['/'])[0] try: print "* Changing path to:", self.pretty_path(target) os.chdir(target) print "* Path is now:", self.pretty_path(os.getcwd()) except: print "! Error:", sys.exc_info()[1] print "* Path is now:", self.pretty_path(os.getcwd()) def f_mkdir(self, argv): if (len(argv) != 2): print "* Usage: mkdir dirname" return 0 target = argv[1] if os.path.exists(target): print "! Error: Exists -", self.pretty_path(os.path.abspath(target)) return 0 try: print "* Creating dir:", self.pretty_path(target) os.mkdir(target) print "* Made at:", self.pretty_path(os.path.abspath(target)) except: print "! Error:", sys.exc_info()[1] def f_cat(self, argv): if (len(argv) != 2): print "* Usage: cat file" return 0 target = argv[1] if (not os.path.exists(target)): print "! Error: Not found -", self.pretty_path(os.path.abspath(target)) return 0 if (os.path.isdir(target)): print "! Error: Target is a directory." return 0 try: f = open(target) contents = f.read() f.close() print contents print "" except: print "! Error:", sys.exc_info()[1] def f_rm(self, argv): if (len(argv) < 2): print "* Usage: rm file [..]" return 0 for file in argv[1:]: full_file = os.path.abspath(file).rstrip('/') if not os.path.exists(file): print "! Error: Not found -", self.pretty_path(file) continue if (full_file.lower() == os.getcwd().rstrip('/').lower()): print "! Error: Skipped rm of current dir (.)" continue if (os.path.isdir(full_file)): try: shutil.rmtree(full_file, True) if (os.path.exists(full_file)): print "! Error: Could not rm -", self.pretty_path(file) else: print "* rm'd:", self.pretty_path(full_file) except: print "! Error:", sys.exc_info()[1] else: try: os.remove(full_file) print "* rm'd:", self.pretty_path(full_file) except: print "! Error:", sys.exc_info()[1] def f_cp(self, argv): if (not (len(argv) >= 3)): print "* Usage: cp src [..] dest" return 0 dest = argv[-1] files = argv[1:-1] if (len(files) > 1): # Copying multiple files, destination must be an existing directory. if (not os.path.isdir(dest)): print "! Error: No such dir -", self.pretty_path(os.path.abspath(dest)) return 0 full_dest = os.path.abspath(dest).rstrip('/') + '/' did_copy = False for file in files: full_file = os.path.abspath(file).rstrip('/') file_name = os.path.basename(full_file) new_name = full_dest + file_name if (not os.path.exists(full_file)): print "! Error: Skipped, missing -", self.pretty_path(file) continue if (full_file.lower() == os.getcwd().rstrip('/').lower()): print "! Error: Skipped cp of current dir (.)" continue try: if (os.path.isdir(full_file)): shutil.copytree(full_file,new_name) else: shutil.copy(full_file,new_name) print "* cp'd:", self.pretty_path(full_file) did_copy = True except: "! Error:", sys.exc_info()[1] if (did_copy): print "* ..to:", self.pretty_path(full_dest) else: # Copying a single file to a (pre-existing) directory or a file file = files[0] full_file = os.path.abspath(file).rstrip('/') file_name = os.path.basename(full_file) full_dest = os.path.abspath(dest).rstrip('/') if (os.path.isdir(full_dest)): if (os.path.exists(full_file)): try: shutil.copytree(full_file,full_dest + '/' + file_name) print "* cp'd:", self.pretty_path(full_file) print "* ..to:", self.pretty_path(full_dest + '/' + file_name) except: print "! Error:", sys.exc_info()[1] else: print "! Error: No such file -", self.pretty_path(file) return 0 else: if (os.path.exists(full_file)): try: shutil.copy(full_file,full_dest) print "* cp'd:", self.pretty_path(full_file) print "* ..to:", self.pretty_path(full_dest) except: print "! Error:", sys.exc_info()[1] else: print "! Error: No such file -", self.pretty_path(file) return 0 def f_mv(self, argv): if (not (len(argv) >= 3)): print "* Usage: mv src [..] dest" return 0 dest = argv[-1] files = argv[1:-1] if (len(files) > 1): # Moving multiple files, destination must be an existing directory. if (not os.path.isdir(dest)): print "! Error: No such dir -", self.pretty_path(os.path.abspath(dest)) return 0 full_dest = os.path.abspath(dest).rstrip('/') + '/' did_move = False for file in files: full_file = os.path.abspath(file).rstrip('/') file_name = os.path.basename(full_file) new_name = full_dest + file_name if (not os.path.exists(full_file)): print "! Error: Skipped, missing -", self.pretty_path(file) continue if (full_file.lower() == os.getcwd().rstrip('/').lower()): print "! Error: Skipped mv of current dir (.)" continue try: os.rename(full_file,new_name) print "* mv'd:", self.pretty_path(full_file) did_move = True except: "! Error:", sys.exc_info()[1] if (did_move): print "* ..to:", self.pretty_path(full_dest) else: # Moving a single file to a (pre-existing) directory or a file file = files[0] full_file = os.path.abspath(file).rstrip('/') file_name = os.path.basename(full_file) full_dest = os.path.abspath(dest).rstrip('/') if (os.path.isdir(full_dest)): if (os.path.exists(full_file)): try: os.rename(full_file, full_dest + '/' + file_name) print "* mv'd:", self.pretty_path(full_file) print "* ..to:", self.pretty_path(full_dest + '/' + file_name) except: print "! Error:", sys.exc_info()[1] else: print "! Error: No such file -", self.pretty_path(file) return 0 else: if (os.path.exists(full_file)): try: os.rename(full_file, full_dest) print "* mv'd:", self.pretty_path(full_file) print "* ..to:", self.pretty_path(full_dest) except: print "! Error:", sys.exc_info()[1] else: print "! Error: No such file -", self.pretty_path(file) return 0 def f_pwd(self, argv): print self.pretty_path(os.getcwd()) def chunk_report(self, bytes_so_far, chunk_size, total_size): if (total_size != None): percent = float(bytes_so_far) / total_size percent = round(percent*100, 2) print "Downloaded %d of %d bytes (%0.2f%%)" % (bytes_so_far, total_size, percent) if bytes_so_far >= total_size: print "" else: print "Downloaded %d bytes" % (bytes_so_far) def chunk_read(self, response, chunk_size=8192, report_hook=None, filename=None): file_data = [] if response.info().has_key('Content-Length'): total_size = response.info().getheader('Content-Length').strip() total_size = int(total_size) else: # No size total_size = None print "* Warning: No total file size available." if (filename == None) and (response.info().has_key('Content-Disposition')): # If the response has Content-Disposition, we take file name from it try: filename = response.info()['Content-Disposition'].split('filename=')[1] if filename[0] == '"' or filename[0] == "'": filename = filename[1:-1] except: filename = "output" if (filename == None): print "* No detected filename, using 'output'" filename = "output" bytes_so_far = 0 while True: chunk = response.read(chunk_size) bytes_so_far += len(chunk) if not chunk: break else: file_data.append(chunk) report_hook(bytes_so_far, chunk_size, total_size) return (file_data, filename) def f_get(self, argv): if (not (2 <= len(argv) <= 3)): print "* Usage: get URL [file]" return 0 target = argv[1] output = (argv[2:] or [None])[0] if (not (target.lower().startswith('http://') or target.lower().startswith('https://'))): print "* Error: URL must start with http:// or https://" return 0 headers = {'User-Agent' : "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6;en-US; rv:1.9.2.9) Gecko/20100824 Firefox/3.6.9"} req = urllib2.Request(target, headers=headers) print "* Downloading:", target response = urllib2.urlopen(req) if (output == None): try: output = target.split('/')[-1].split('#')[0].split('?')[0] finally: if (not output): output = None data,filename = self.chunk_read(response, report_hook=self.chunk_report, filename=output) if (len(data) > 0): try: f = open(filename, "wb") for x in data: f.write(x) f.close() print "* Saved to:", self.pretty_path(filename) except: print "! Error:", sys.exc_info()[1] else: print "* Error: 0 bytes downloaded, not saved" def f_exit(self, argv): print "*** Exiting shpy ***" return 1 def f_pypi(self, argv): print "pypi commands:\n" + \ "--------------\n" + \ "pypi-search [-f] name - Top/all package search\n" + \ "pypi-vers [-f|-v] name - Top/all/visible vers\n" + \ "pypi-install name [version] - Download src package" return 0 def f_pypi_install(self, argv): if (not (len(argv) >= 2)): print "* Usage: pypi-install name [version]" return 0 pkg_name = argv[1] pkg_ver = (argv[2:] or [''])[0] pypi = xmlrpclib.ServerProxy('http://pypi.python.org/pypi') hits = pypi.package_releases(pkg_name, True) if (not hits): print "* PyPI: No package named:", pkg_name return 0 if (not pkg_ver): pkg_ver = hits[0] elif (not (pkg_ver in hits)): print "* PyPI: Version '%s' not available for package '%s'" % (pkg_ver, pkg_name) return 0 hits = pypi.release_urls(pkg_name, pkg_ver) if (not hits): print "* PyPI: No src for version '%s' of package '%s'" % (pkg_ver, pkg_name) return 0 source = ([x for x in hits if x['packagetype'] == 'sdist'][:1] + [None])[0] if (not source): print "* PyPI: No src for version '%s' of package '%s'" % (pkg_ver, pkg_name) return 0 return self.f_get([None, source['url'], source['filename']]) def f_pypi_search(self, argv): if (not (len(argv) >= 2)): print "* Usage: pypi-search name" return 0 no_limit = False if ((len(argv) > 2) and (argv[1] in ["-f"])): if (argv[1] == '-f'): no_limit = True argv = argv[1:] pkg_name = ' '.join(argv[1:]) pypi = xmlrpclib.ServerProxy('http://pypi.python.org/pypi') hits = pypi.search({'name': pkg_name}, 'and') if (not hits): print "* PyPI: No matches found." return 0 if ((not no_limit) and (len(hits) > 5)): hits = hits[:5] elif (not no_limit): no_limit = True if (not no_limit): print "* Top 5 matches:" else: print "* Found %s match%s:" % (len(hits), ((len(hits) > 1) and 'es') or '') for p in sorted(hits, key=lambda pkg: pkg['_pypi_ordering'], reverse=True): print " %s:" % (p['name']) print ' "%s"' % (p['summary']) def f_pypi_vers(self, argv): if (not (len(argv) >= 2)): print "* Usage: pypi-vers [-f|-v] name" return 0 no_limit,show_hidden = False, True if ((len(argv) > 2) and (argv[1] in ["-f","-v"])): if (argv[1] == '-f'): no_limit = True elif (argv[1] == '-v'): show_hidden = False argv = argv[1:] pkg_name = ' '.join(argv[1:]) pypi = xmlrpclib.ServerProxy('http://pypi.python.org/pypi') hits = pypi.package_releases(pkg_name, show_hidden) if (not hits): print "* PyPI: None available for:", pkg_name return 0 if ((not no_limit) and (len(hits) > 10)): hits = hits[:10] elif (not no_limit): no_limit = True if (not no_limit): leader = "Top 10" elif (not show_hidden): leader = "Visible" else: leader = "Available" print "* %s version%s:" % (leader, (((len(hits) > 1) and 's') or '')) print ', '.join(hits) def f_unzip(self, argv): # filename, location if (not (2 <= len(argv) <= 3)): print "* Usage: unzip file.zip [destdir]" return 0 filename = os.path.abspath(argv[1]) if (not filename.lower().endswith('.zip')): print "! Error: Needs a .zip name -", self.pretty_path(argv[1]) return 0 location = (argv[2:3] or [os.path.dirname(filename) + "/" + os.path.splitext(os.path.basename(filename))[0]])[0] if not os.path.exists(filename): print "! Error: No such file -", self.pretty_path(argv[1]) return 0 if not os.path.exists(location): os.makedirs(location) zipfp = open(filename, 'rb') try: print "* Unzipping:", self.pretty_path(filename) print "* To path:", self.pretty_path(os.path.abspath(location)) zip = zipfile.ZipFile(zipfp) leading = self.has_leading_dir(zip.namelist()) for name in zip.namelist(): data = zip.read(name) fn = name if leading: fn = self.split_leading_dir(name)[1] fn = os.path.join(location, fn) dir = os.path.dirname(fn) if not os.path.exists(dir): os.makedirs(dir) if fn.endswith('/') or fn.endswith('\\'): # A directory if not os.path.exists(fn): os.makedirs(fn) else: fp = open(fn, 'wb') try: fp.write(data) finally: fp.close() except: zipfp.close() print "! Error: Bad .zip / problem unzipping" return 0 finally: zipfp.close() def f_webdav(self, argv): # filename, location import types, socket try: davcheck = __import__('DAV') davScheck = __import__('DAVServer') if ((type(davcheck) == types.ModuleType) and (type(davScheck) == types.ModuleType)): davready = True except: davready = False olddir = os.path.abspath(os.getcwd()) if (not davready): # Do a little work to pull down the modules to near shpy import inspect target = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe()))) os.chdir(target) self.parse_cmd(self.bp.bash_parse("rm PyWebDAV*.tar.gz")) self.parse_cmd(self.bp.bash_parse("pypi-install PyWebDAV")) self.parse_cmd(self.bp.bash_parse("untar PyWebDAV*.tar.gz")) self.parse_cmd(self.bp.bash_parse("rm PyWebDAV*.tar.gz")) self.parse_cmd(self.bp.bash_parse("mv PyWebDAV*/DAV .")) self.parse_cmd(self.bp.bash_parse("mv PyWebDAV*/DAVServer .")) self.parse_cmd(self.bp.bash_parse("rm PyWebDAV*")) from DAVServer.fileauth import DAVAuthHandler as pywebdavauthhandler from DAVServer import server as pywebdavserver os.chdir(olddir) try: s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) s.connect(("www.google.com",80)) hostname = s.getsockname()[0] s.close() except: hostname = socket.gethostbyname(socket.gethostname()) _dc = { 'verbose' : False, 'directory' : os.getcwd(), 'port' : 8008, 'host' : hostname, 'noauth' : True, 'user' : '', 'password' : '', 'daemonize' : False, 'daemonaction' : 'start', 'counter' : 0, 'lockemulation' : True, 'mimecheck' : True, 'chunked_http_response': 1, 'http_request_use_iterator': 0, 'http_response_use_iterator': 0, 'baseurl' : ''} conf = pywebdavserver.setupDummyConfig(**_dc) handler = pywebdavauthhandler handler._config = conf print "*** STARTING WEBDAV ***" print "*** WebDAV url:" print " http://%s:8008/" % (hostname) print "*** NOTE: Using Windows?" print "*** If so, recommend use 'BitKnex'" pywebdavserver.runserver(port=8008, host=hostname, directory=os.getcwd(), verbose=True, noauth=True, user='', password='', handler=handler) return 0 def f_untar(self, argv): # filename, location if (not (2 <= len(argv) <= 3)): print "* Usage: untar file.tar [destdir]" return 0 filename = os.path.abspath(argv[1]) if (not (filename.lower().endswith('.tar') or filename.lower().endswith('.tgz') or filename.lower().endswith('.tar.gz'))): print "! Error: Needs a .tar/.tar.gz/.tgz name -", self.pretty_path(argv[1]) return 0 elif filename.lower().endswith('.tar.gz'): base_filename = os.path.basename(filename)[:-7] else: base_filename = os.path.splitext(os.path.basename(filename))[0] location = (argv[2:3] or [os.path.dirname(filename) + "/" + base_filename])[0] if not os.path.exists(location): os.makedirs(location) if filename.lower().endswith('.gz') or filename.lower().endswith('.tgz'): mode = 'r:gz' else: mode = 'r' tar = tarfile.open(filename, mode) try: leading = self.has_leading_dir([member.name for member in tar.getmembers() if member.name != 'pax_global_header']) print "* Untarring:", self.pretty_path(filename) print "* To path:", self.pretty_path(os.path.abspath(location)) for member in tar.getmembers(): fn = member.name if fn == 'pax_global_header': continue if leading: fn = self.split_leading_dir(fn)[1] path = os.path.join(location, fn) if member.isdir(): if not os.path.exists(path): os.makedirs(path) elif member.issym(): # skip symlinks print "! Skipped symlink -", member.name continue else: try: fp = tar.extractfile(member) except (KeyError, AttributeError): e = sys.exc_info()[1] print "! Error: Invalid -", member.name, ":", e continue if not os.path.exists(os.path.dirname(path)): os.makedirs(os.path.dirname(path)) destfp = open(path, 'wb') try: shutil.copyfileobj(fp, destfp) finally: destfp.close() fp.close() finally: tar.close() def f_selfupdate(self, argv): self.f_get(['get', 'https://raw.github.com/pudquick/PythonForiOSPatches/master/shpy/shpy.py']) def f_vars(self, argv): for k in sorted(self.bp.env_vars.keys()): print "%s: %s" % (k, self.bp.env_vars[k]) def f_error(self, argv): if (argv[:1]): print "! Unknown cmd: %s - try: help" % argv[0] else: print "! Unknown cmd - try: help" def __init__(self): # Hiding away BashParser from a wildcard import of shpy # Let's keep those globals tidy! from bash_alike import BashParser self.available_cmds = {"quit": self.f_exit, "logout": self.f_exit, "exit": self.f_exit, "help": self.f_help, "h": self.f_help, "?": self.f_help, "cd": self.f_cd, "pwd": self.f_pwd, "mv": self.f_mv, "cp": self.f_cp, "rm": self.f_rm, "ls": self.f_ls, "dir": self.f_ls, "cat": self.f_cat, "get": self.f_get, "curl": self.f_get, "wget": self.f_get, "mkdir": self.f_mkdir, "untar": self.f_untar, "unzip": self.f_unzip, "vars": self.f_vars, "webdav": self.f_webdav, "pypi": self.f_pypi, "pypi-search": self.f_pypi_search, "pypi-vers": self.f_pypi_vers, "pypi-install": self.f_pypi_install, "selfupdate": self.f_selfupdate} self.hmsg = "Available commands:\n" + \ "-------------------\n" + \ "help - Shows help (also: h, ?)\n" + \ "exit - Quits shpy (also: logout, quit)\n" + \ "pwd - Show current directory\n" + \ "ls [file ..] - List file(s)\n" + \ "cd [dir] - Change directory\n" + \ "mkdir dir - Create directory\n" + \ "cat file - Print file to screen\n" + \ "unzip file.zip [destdir] - Unzip file\n" + \ "untar file.tar [destdir] - Untar file\n" + \ "rm file [..] - Delete files and dirs\n" + \ "mv src [..] dest - Move file(s)\n" + \ "cp src [..] dest - Copy file(s)\n" + \ "get URL [file] - Download file\n" + \ "selfupdate - Update shpy\n" + \ "pypi - Show available PyPI commands\n" + \ "webdav - Run a webdav server in cwd\n" + \ "vars - List variables and values" self.bp = BashParser() try: dir = [x for x in sys.path if ('Python for iOS.app' in x)][0].split('Python for iOS.app')[0] if (dir.startswith('/var')): dir = '/private' + dir except: dir = '/' documents = dir + 'Documents' modules = documents + '/Modules' scripts = documents + '/User Scripts' if (os.getcwd() == '/'): # Chances are we're being run without _rp os.chdir(scripts) env_vars = {'$HOME': documents, '$SCRIPTS': scripts, '$MODULES': modules} self.bp.env_vars = env_vars def pretty_path(self, path_string): base = self.bp.env_vars['$HOME'].rstrip('/') if ((base == '') or (not path_string.startswith(base))): return path_string fixed = path_string[len(base):] if (fixed): return '~' + fixed return '~/' def parse_cmd(self, argv): cmd = (argv[:1] or [None])[0] return (self.available_cmds.get(cmd, self.f_error))(argv) def fixed_raw_input(self, prompt): # Temporary workaround for ongoing bug in Python for iOS sys.stdout.write(prompt) sys.stdout.flush() return raw_input().rstrip('\r\n') def main_loop(self): while True: command_str = self.fixed_raw_input('$> ') try: command_list = self.bp.bash_parse(command_str) if (command_list): if (self.parse_cmd(command_list)): return except SyntaxError, msg: print "*** Error:", msg except: