Ksh-ish functionality on Unix systems

Donn Cave donn at u.washington.edu
Thu Sep 20 20:18:59 EDT 2001


Quoth weeks at vitus.scs.agilent.com (Greg Weeks):

| My operating system is Unix.  One decision that I would like to eliminate
| when I"m faced with a small programming task is: Ksh or Python?  I'd like
| to just reach for Python.
|
| Here are some things that Ksh does conveniently:
|
|     <  >  >>  2>  2>>  2>&1		# REDIRECTION
|     &					# BACKGROUND
|     |					# PIPING
|     $() or ``				# CAPTURING STDOUT
|
| And here is what I find in Python:
|
|   LOW LEVEL:
|     os:  open pipe dup2 close fork execv waitpid
|   HIGHER LEVEL:
|     os:        system
|     os:        popen
|     commands:  getstatusoutput
|     popen2:    *
|
| The low-level support is far too verbose for casual use.  The higher-level
| stuff seems incomplete.  However, the higher-level stuff becomes a lot more
| complete if the command arguments are passed to, say, /bin/sh on Unix
| systems.  In that case, os.system and getstatusoutput capture the above Ksh
| functionality, and os.popen and popen2.* are bonuses.
|
| So: Is it a reasonable approach as a Unix user to rely on the fact that the
| os.system and getstatusoutput commands are passed to a shell?
|
| Or is that tacky?  If that *is* tacky, is there a *convenient* alternative?

system() and getstatusoutput() will indeed invoke the shell, that's
a given.  What's tacky about that is a multiple evaluation problem,
when you construct the shell command out of input data from some not
entirely predictable source.  When the shell evaluates its command line,
results are lowered to another, unpleasant dimension of unpredictability.
You can cut the shell out of the equation, with popen2 (only if you pass
a sequence of arguments) and os.spawnv.  But of course that loses your
redirections and other shell conveniences.  If your commands are known,
not going to have accidental shell metacharacters etc., then it's quite
OK to call system, and Bourne shell redirections are fine there.

| PS: Wishfully thinking, I tried re-assigning sys.output.  But that rebinds
| the stream, not the file-descriptor.

Yep.  It isn't much easier than os.dup2(fd, 1) anyway.  You can look
at commands.py, popen2.py etc., probably already have, and if you
know what would be easy for you, you can write your own.   How about
something like this:

     try:
         result = ecmd.ecmd('lx', ('lx', '-s', 'hi'), fromfile = open('spud', 'r'))
     except ecmd.ECmdError, val:
         print 'lx error:', val
     else:
         print 'lx output:', result

I don't think raising an exception is overkill at all, it's a really
basic principle of Python that we don't continue past an error without
accounting for it somehow.

	Donn Cave, University Computing Services, University of Washington
	donn at u.washington.edu



More information about the Python-list mailing list