Re: Python as standard shell? was Re: [RFC] Draft Proposal

Bill Janssen (janssen@parc.xerox.com)
Tue, 31 May 1994 19:58:37 PDT

Let's try that again, without line folding:

#
# Simple UNIX shell with Python underneath.
#
#
# Syntax:
#
# COMMAND ARG ARG ARG
#
# if COMMAND doesn't begin with a hyphen [-], and if an executable by
# that name is found on the UNIX path, the command line is executed in a
# Bourne shell. If COMMAND begins with a hyphen, or if no executable is
# found on the UNIX path, the hyphen is stripped and the resulting line
# is passed to Python for evaluation.
#
# $Id: sh.py,v 1.2 1994/06/01 02:32:30 janssen Exp janssen $
#

#######################################################################
### Imported modules
#######################################################################

import sys, posix, posixpath, string, os, glob

#######################################################################
### Global variables
#######################################################################

DefaultPromptString = "%(cwd)s > "
PromptVars = {}
Prompt = DefaultPromptString # what to prompt with
BuiltinCommands = {} # commands that should be recognized as python commands, even if UNIX commands exist

_dir_stack = []

#######################################################################
### Exceptions
#######################################################################

InvalidDirectory = 'Specified directory does not exist'
BadArgumentCount = 'Invalid number of arguments passed'

#######################################################################
### Utility functions
#######################################################################

# read hostname

def _figure_hostname():
file = posix.popen ('hostname', 'r')
hostname = file.read()
while hostname[len(hostname) - 1] == '\n':
hostname = hostname[0:(len(hostname) - 1)]
return hostname

def _getcwd ():
dir = posix.getcwd()
if (string.find(dir, "/tmp_mnt/") == 0):
dir = dir[8:]
if (string.find(dir, "/tilde/") == 0):
dir = '~' + dir[7:]
return (dir)

def is_executable (filename):
try:
if (posixpath.isfile(filename)):
mode = posix.stat(filename)[0]
if ((mode & 0500) == 0500 or (mode & 0050) == 0050 or (mode & 0005) == 0005):
return 1
return 0
except:
print 'whoa! exception in is_executable!'
print 'type: ', sys.exc_type, '\nvalue: ', sys.exc_value

def find_on_path (command):
try:
if (is_executable(command)):
return 1
for dir in string.splitfields(posix.environ['PATH'], ':'):
if (is_executable(dir + '/' + command)):
return 1
except:
pass
return 0

def cd (args):
global PromptVars
if (len(args) > 2):
raise BadArgumentCount
if (len(args) < 2):
dir = '~'
else:
dir = args[1]
dir = posixpath.expanduser(posixpath.expandvars(dir))
if (posixpath.isdir(dir)):
posix.chdir (dir)
PromptVars['cwd'] = _getcwd()
else:
dir = './' + dir
if (posixpath.isdir(dir)):
posix.chdir (dir)
PromptVars['cwd'] = _getcwd()
else:
raise InvalidDirectory

def pushdir (args):
global PromptVars
if (len(args) != 2):
raise BadArgumentCount
dir = posixpath.expanduser(posixpath.expandvars(args[1]))
if (posixpath.isdir(dir)):
_dir_stack.insert (0, _getcwd())
posix.chdir (dir)
PromptVars['cwd'] = _getcwd()
else:
dir = './' + dir
if (posixpath.isdir(dir)):
_dir_stack.insert (0, _getcwd())
posix.chdir (dir)
PromptVars['cwd'] = _getcwd()
else:
raise InvalidDirectory

def popdir (junk):
if (len(junk) != 1):
raise BadArgumentCount
if (len(_dir_stack) > 0):
dir = posixpath.expanduser(posixpath.expandvars(_dir_stack[0]))
del _dir_stack[0]
if (posixpath.isdir(dir)):
posix.chdir(dir)
PromptVars['cwd'] = _getcwd()
else:
sys.stderr.write ('No such directory %s\n' % (dir))
raise InvalidDirectory
else:
raise InvalidDirectory

def show_dir_stack (junk):
sys.stderr.write ('%s\n' % (_dir_stack))

#######################################################################
### The main interpreter
#######################################################################

def do_builtin_command (tokens):
try:
fn = BuiltinCommands[tokens[0]]
if fn:
fn (tokens)
else:
sys.stderr.write ('No function for builtin command <%s>!' % (tokens[0]))
except:
sys.stderr.write('Builtin %s signals: %s (%s)\n' % (tokens, sys.exc_type, sys.exc_value))

def do_python_command (tokens):
import sh
try:
if (len(tokens) == 1 and tokens[0][0] == '$'):
s = posix.environ[tokens[0][1:]]
else:
s = eval(string.join(tokens))
sys.stderr.write(str(s) + '\n')
except:
# assume it's really a statement...
try:
exec string.join(tokens)
except:
sys.stderr.write('bad Python command: <%s>\n%s (%s)\n%s\n' % (string.join(tokens), sys.exc_type, sys.exc_value))

def do_unix_command(tokens):
def _joinfiles (a, b): return a + b
def _globfile (f):
if (f[0] == '$'):
globbed = posix.environ[f[1:]]
else:
globbed = glob.glob(f)
if (len(globbed) == 0):
return [ f ]
else:
return globbed
try:
command = string.join(reduce(_joinfiles, map(_globfile, tokens)))
val = posix.system(command)
if (val <> 0):
sys.stderr.write('%x\n' % (val))
except:
sys.stderr.write("Can't exec command <%s>: %s (%s)\n" % (tokens, sys.exc_type, sys.exc_value))

def getcommand ():
global Prompt, PromptVars
try:
if (type(Prompt) == type('')):
p = Prompt % PromptVars
elif (type(Prompt) == type(getcommand)):
p = Prompt(PromptVars)
return (raw_input(p))
except EOFError:
sys.exit(0)
except:
sys.stderr.write ('Bad prompt string, reverting to default "%s"\n' % (DefaultPromptString))
Prompt = DefaultPromptString
try:
return (raw_input(Prompt % PromptVars))
except EOFError:
sys.exit(0)
except:
sys.stderr.write ("Can't read input!!\n")
sys.exit(0)

def shell():
global BuiltinCommands
command = getcommand()
while command:
try:
tokens = string.split(command)
if tokens[0][0] == '-':
tokens[0] = tokens[0][1:]
junk = do_python_command(tokens)
elif BuiltinCommands.has_key(tokens[0]):
junk = do_builtin_command(tokens)
elif find_on_path(tokens[0]):
junk = do_unix_command(tokens)
else:
junk = do_python_command(tokens)
except:
pass
command = getcommand()

#######################################################################
### Module initialization
#######################################################################

PromptVars['hostname'] = _figure_hostname()
PromptVars['cwd'] = _getcwd()

BuiltinCommands['cd'] = cd
BuiltinCommands['pushd'] = pushdir
BuiltinCommands['popd'] = popdir
BuiltinCommands['dirs'] = show_dir_stack