Programming Forums
User Name Password Register
 

RSS Feed
FORUM INDEX | TODAY'S POSTS | UNANSWERED THREADS | ADVANCED SEARCH

Reply
 
Thread Tools Display Modes
Old Nov 25th, 2006, 8:53 PM   #1
bulio
Hobbyist Programmer
 
bulio's Avatar
 
Join Date: Jul 2004
Location: Location
Posts: 138
Rep Power: 5 bulio is on a distinguished road
Python shell help

Hi everyone,

For the fun of it, I am trying to write a shell program similar to Linux's bash or Windows' command. I'm writing the program on Windows, and this is what I have so far:

import os

os.chdir('/') #Change the directory to Windows root

while True:
    directory = os.path.abspath(os.curdir) 
    directory += '>>'
    prompt = raw_input(directory) #Print the command line prompt as C:\>>

So far, it waits for the user's input by looping C:\>>.

My next step is to actually make the shell respond to user commands. For example, if the user inputs put "Text here" the shell will interpret the statement as print "Text here".

I think the best thing to use is a parser or string methods. The problem is that I haven't found many docs on either item, and am not sure how to implement this. Does anyone here have a tutorial or an example on how I would parse text so that python can interpret it and do what I want? (I also want to do things such as change directory with a command like dir <dir here> and so on.)

Thanks
bulio is offline   Reply With Quote
Old Nov 25th, 2006, 9:07 PM   #2
Darkhack
Hobbyist Programmer
 
Darkhack's Avatar
 
Join Date: Dec 2005
Location: Kansas City
Posts: 102
Rep Power: 3 Darkhack is on a distinguished road
Send a message via AIM to Darkhack
I would read up on parsers or interpreters. Complexity is also a big part of it. You might think of having a tokenizer if you plan to have long or complex commands. Otherwise a simple <command attrib1 attrib2 attrib3> could be done with simple string parsing.

I'm not familiar with Python myself but read the string and seperate each word in an array. Item zero would be your command and the rest would be the attributes passed to it. From there you can use a series of if-statements to determine what functions to use.
Darkhack is offline   Reply With Quote
Old Nov 25th, 2006, 9:11 PM   #3
titaniumdecoy
Expert Programmer
 
titaniumdecoy's Avatar
 
Join Date: Nov 2005
Posts: 843
Rep Power: 3 titaniumdecoy is on a distinguished road
Send a message via AIM to titaniumdecoy
The str.split function is extremely useful. For example, "slice me up".split() produces the list ['slice', 'me', 'up'].
titaniumdecoy is offline   Reply With Quote
Old Nov 25th, 2006, 9:44 PM   #4
bulio
Hobbyist Programmer
 
bulio's Avatar
 
Join Date: Jul 2004
Location: Location
Posts: 138
Rep Power: 5 bulio is on a distinguished road
.split() may work, but how would I use that to determine if the user wrote put or not?
bulio is offline   Reply With Quote
Old Nov 25th, 2006, 10:00 PM   #5
Darkhack
Hobbyist Programmer
 
Darkhack's Avatar
 
Join Date: Dec 2005
Location: Kansas City
Posts: 102
Rep Power: 3 Darkhack is on a distinguished road
Send a message via AIM to Darkhack
This might help. You simply use an if-statement on your array.

http://www.ibiblio.org/g2swap/byteof...statement.html
Darkhack is offline   Reply With Quote
Old Nov 25th, 2006, 10:10 PM   #6
Sane
Programming Guru
 
Sane's Avatar
 
Join Date: Apr 2005
Location: Waterloo, Ontario
Posts: 1,835
Rep Power: 5 Sane will become famous soon enough
Send a message via MSN to Sane
Quote:
Originally Posted by Darkhack View Post
This might help. You simply use an if-statement on your array.

http://www.ibiblio.org/g2swap/byteof...statement.html
BURN!!!! Hahahaha.

I'm sure that wasn't actually your question. You should probably specify what you mean by that. Are you talking about case-sensitive circumstances, or situations where there may be other garbage tagged along with it?

Or are you talking about how you could elegantly link each command to a different function call, without repetitive code?

I'd look into the idea of using a dictionary to map each command to a function call:
def output (*args):
    print args[0][0]

def list_of_files (*args):
    pass

def run_file (*args):
    pass

# parse the input in to a command and list of parameters
command = 'put'
params = ['"Text Here"']

# turn the command into a function pointer
commands = {"put":output, "dir":list_of_files, "start":run_file}
function = commands[command]

# call the function pointer with the parsed parameters
function (params)
Sane is offline   Reply With Quote
Old Nov 26th, 2006, 6:06 AM   #7
Arevos
Programming Guru
 
Arevos's Avatar
 
Join Date: Aug 2005
Location: England
Posts: 1,499
Rep Power: 5 Arevos is on a distinguished road
Quote:
Originally Posted by bulio View Post
For the fun of it, I am trying to write a shell program similar to Linux's bash or Windows' command.
Funnily enough, every so often I try to do exactly the same thing. Though for my next attempt I think I'll use Haskell.

My advice is to look into a parser generator like PyParsing. You could use this to define a simple grammar:
python Syntax (Toggle Plain Text)
  1. from pyparsing import CharsNotIn, OneOrMore, Empty
  2.  
  3. string = CharsNotIn(" '\"")
  4. command = OneOrMore(string + Empty())
  5. line = command | Empty()
This defines a string as consisting of any character apart from a space or a quotation mark. A command (plus arguments) consists of number of strings, and a line can either be a command, or it can be empty.

Aha, you might very well say, but why does it say OneOrMore(string + Empty()), rather than OneOrMore(string)? Unfortunately, I forget the exact reason, as I've lost the email where I quizzed the creator of PyParsing about it. However, IIRC it has to do with conflicts between PyParsing's whitespace handling and any sufficiently broad CharsNotIn - the Empty() object ensures that the grammar is parsed unambiguously.

Anyway, once you have your grammar, you can define some commands to go with it. In Unix, there are functions to resolve the command PATH, but in Windows those functions appear to be absent, so I think we have to create our own. If anyone finds a better solution, please tell me:
python Syntax (Toggle Plain Text)
  1. import os
  2.  
  3. PATHS = ["/bin", "/usr/bin"]
  4.  
  5. def find_command(name):
  6. for path in PATHS:
  7. filepath = os.path.join(path, name)
  8. if os.path.isfile(filepath):
  9. return filepath
  10.  
  11. def exec_command(string, location, tokens):
  12. os.spawnv(os.P_WAIT, find_command(tokens[0]), tokens[:])
The find_command function should be pretty obvious. The exec_command function is designed to accept output from PyParsing. It contains three arguments: the substring that was parsed, the location of the substring, and a list of parsed tokens. Usually one is only interested in the tokens, which in this case will be a command plus its arguments.

The exec_command function uses os.spawnv to execute an external command with a set of arguments. Of course, this function could just as easily execute internal functions as well, or indeed do whatever you wish.

The next step is to associate exec_command with the command grammar object:
python Syntax (Toggle Plain Text)
  1. command.setParseAction(exec_command)
Which is simple enough. Then it's a case of constructing a simple command line loop:

python Syntax (Toggle Plain Text)
  1. while True:
  2. try:
  3. input = raw_input(">> ")
  4. except EOFError:
  5. break
  6. else:
  7. line.parseString(input)
One could forgo PyParsing and use string.split instead to get the tokens. However, unlike a simple split function, a parsing system like PyParsing is rather more flexible, allowing you to insert control structures and other more complex functionality with relative ease.
Arevos is offline   Reply With Quote
Reply

Bookmarks

« Previous Thread in Forum | Next Thread in Forum »

Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
 
Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Forum Jump

Similar Threads
Thread Thread Starter Forum Replies Last Post
[tutorial] Python for programming beginners coldDeath Python 30 Dec 14th, 2005 11:35 AM
Convert Python script to C++ code clanotheduck Python 17 Sep 25th, 2005 8:55 AM
Advanced Python Tricks Arevos Python 19 Sep 24th, 2005 7:39 AM
Hybrid python shell Arevos Existing Project Development 0 Sep 22nd, 2005 4:37 PM
Python - A Programmers Introduction coldDeath Python 17 Aug 19th, 2005 12:41 PM




DaniWeb IT Discussion Community
All times are GMT -5. The time now is 12:08 PM.

Powered by vBulletin® Version 3.7.0, Copyright ©2000 - 2008, Jelsoft Enterprises Ltd.
Copyright ©2007 DaniWeb® LLC