473,748 Members | 2,361 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

porting shell scripts: system(list), system_pipe(lis ts)

One of my recent projects has involved taking an accretion of sh and
perl scripts and "doing them right" - making them modular, improving
the error reporting, making it easier to add even more features to
them. "Of course," I'm redoing them in python - much of the cut&paste
reuse has become common functions, which then get made more robust and
have a common style and are callable from other (python) tools
directly, instead of having to exec scripts to get at them. The usual
"glorious refactoring."

Most of it has been great - os.listdir+i.en dswith() instead of
globbing, exception handling instead of "exit 1", that sort of thing.
I've run into one weakness, though: executing programs.

Python has, of course, os.fork and os.exec* corresponding to the raw
unix functions. It also has the higher level os.system, popen,
expect, and commands.get* functions. The former need a bunch of
stylized operations performed; the latter *all* involve passing in
strings which then leads one to quoting issues, which can be serious
risks in some applications.

Perl had one very helpful interface for this kind of thing: system and
exec will both take array arguments:
$ perl -e 'system("echo", "*")'
*
$ perl -e 'exec("echo", "*")'
*
versus
$ perl -e 'exec("echo *")'
#.newsrc-dribble# CVS stuff ...
This has always struck me as "correct" - not the overloading,
necessarily, but the use of a list.

So, implementing system this way is easy enough:

def system(cmd):
pid = os.fork()
if pid > 0:
p, st = os.waitpid(pid, os.P_WAIT)
if st == 0:
return
raise ExecFailed(str( cmd), st)
elif pid == 0:
try:
os.execvp(cmd[0], cmd)
except OSError, e:
traceback.print _exc()
os._exit(113)

[The try/except is an interesting issue: if cmd[0] isn't found,
os.execvp throws -- but it is already in the child, and this walks up
the stack to any surrounding try/except, which then continues,
possibly disastrously, whatever that code had been doing *in a
duplicate process*. The _exit explicitly short cuts this.]

So, this makes a big difference when porting simple bits of shell (and
usually, just in passing, fixing quoting bugs - if you had code that
used to do "ci -l $foo" and it is now "system(['ci', '-l', foo])"
you now properly handle spaces and punctuation in the value of foo,
"for free".) However, the other thing you tend to find in
"advanced"[1] shell scripts is lengthy pipelines. (Sure, you find
while loops and case statements and such - but python's control
structures handle those fine.)

Implementing pipelines takes rather a bit more work, and one might
(not unreasonably) throw up one's hands and just use os.system and
some re.sub's to do the quoting. However, I had enough cases where
the goal really was to run a complex shell pipeline (I also had cases
where the pipeline converted nicely to some inline python code,
especially with the help of the gzip module) that I sat down and
cooked up a pipeline class.

The interface I ended up with is pretty simple:
g_pipe = pipeline()
g_pipe.stdin(op en("blort.gz", "r"))
g_pipe.append(["gunzip"])
g_pipe.append(["sort", "-u"])
g_pipe.append(["wc", "-l"])
g_pipe.stdout(o pen("blort.coun t", "w"))
print g_pipe.run()

is equivalent to the sh:
gunzip < blort.gz | sort -u | wc -l > blort.count

pipeline also has obvious stderr and chdir methods; pipeline.run
actually returns an array with the return status of *each* pipeline
element (which leads to "if filter(None, st): deal_with_error " being a
useful idiom for noticing failures that a shell script would typically
miss.)

This has lead me to a few questions:

1. Am I being dense? Are there already common modules (included or
otherwise) that do this, or solve the problem some other way?
2. Is there a more pythonic way of expressing the construction?
Would exposing the internal array of commands make more sense,
possibly by "passing through" various array operations on the
class to the internal array (as the use of "append" hints at)? Or
maybe "exec" objects that a "pipe" combiner operates on?
3. Should an interface like this be in a "battery" somewhere? shutil
didn't seem to quite match...
4. Any reason to even try porting this interface to non-unix systems?
Is there a close enough match to os.pipe/os.fork/os.exec/os.wait,
or some other construct that works on microsoft platforms?

_Mark_ <ei****@metacar ta.com>

[1] in the Invader Zim sense :)
Jul 18 '05 #1
2 3370


ei****@metacart a.com wrote:
One of my recent projects has involved taking an accretion of sh and
perl scripts and "doing them right" - making them modular, improving
the error reporting, making it easier to add even more features to
them. "Of course," I'm redoing them in python - much of the cut&paste
reuse has become common functions, which then get made more robust and
have a common style and are callable from other (python) tools
directly, instead of having to exec scripts to get at them. The usual
"glorious refactoring."
<<SNIP>>
Implementing pipelines takes rather a bit more work, and one might
(not unreasonably) throw up one's hands and just use os.system and
some re.sub's to do the quoting. However, I had enough cases where
the goal really was to run a complex shell pipeline (I also had cases
where the pipeline converted nicely to some inline python code,
especially with the help of the gzip module) that I sat down and
cooked up a pipeline class.

The interface I ended up with is pretty simple:
g_pipe = pipeline()
g_pipe.stdin(op en("blort.gz", "r"))
g_pipe.append(["gunzip"])
g_pipe.append(["sort", "-u"])
g_pipe.append(["wc", "-l"])
g_pipe.stdout(o pen("blort.coun t", "w"))
print g_pipe.run()

is equivalent to the sh:
gunzip < blort.gz | sort -u | wc -l > blort.count
<<SNIP>>
_Mark_ <ei****@metacar ta.com>

[1] in the Invader Zim sense :)


I think that your pipeline code looks nothing like the original sh
script pipeline which to me counts heavily against it.
Just playing at the cygwin prompt...
$ ls -l|wc -l > /tmp/lines_in_dir
$ cat /tmp/lines_in_dir
465
$ python
from os import system
system(r'''/bin/ls -l|/bin/wc -l > /tmp/lines_in_dir2'' ') 0 system(r'''/bin/cat /tmp/lines_in_dir2'' ')

463
0

I prefer the above because it looks like the original sh command.
Of course, if script security is very important then you may want to
change the way things are implemented again.

Cheers, Paddy.

Jul 18 '05 #2
Quoth ei****@metacart a.com:
....
| 1. Am I being dense? Are there already common modules (included or
| otherwise) that do this, or solve the problem some other way?

I can't tell you whether any of them has come to be common, but
there have been a handful of efforts along these lines - process
and pipeline creation.

| 2. Is there a more pythonic way of expressing the construction?
| Would exposing the internal array of commands make more sense,
| possibly by "passing through" various array operations on the
| class to the internal array (as the use of "append" hints at)? Or
| maybe "exec" objects that a "pipe" combiner operates on?

Only thing that comes to mind is error handling. It certainly is
not characteristic of Python functions to return an error status,
rather they typically raise exceptions. Ideally, I would think
the exception type for this would carry the exit status, other
information in the status word, and text from error/diagnostic
output. That last one is particularly important and particularly
awkward to get.

See appended example for a trick to deal with the special case
where a Python exception is caught in the fork.

| 3. Should an interface like this be in a "battery" somewhere? shutil
| didn't seem to quite match...

No one ever likes anyone else's version of this, so it's typically
reinvented as required.

| 4. Any reason to even try porting this interface to non-unix systems?
| Is there a close enough match to os.pipe/os.fork/os.exec/os.wait,
| or some other construct that works on microsoft platforms?

There's os.spawnv, if you haven't noticed that.

Donn Cave, do**@drizzle.co m
-----------
import fcntl
import posix
import sys
import pickle

def spawn_wnw(wait, file, args, env):
p0, p1 = posix.pipe()
pid = posix.fork()
if pid:
posix.close(p1)
ps = posix.read(p0, 1024)
posix.close(p0)
if wait:
junk, ret = posix.waitpid(p id, 0)
else:
ret = pid
if ps:
e, v = pickle.loads(ps )
raise e, v
else:
return ret
else:
try:
fcntl.fcntl(p1, fcntl.F_SETFD, fcntl.FD_CLOEXE C)
posix.close(p0)
posix.execve(fi le, args, env)
except:
e, v, t = sys.exc_info()
s = pickle.dumps((e , v))
posix.write(p1, s)
posix._exit(117 )

def spawnw(file, args, env):
spawn_wnw(1, file, args, env)

def spawn(file, args, env):
spawn_wnw(0, file, args, env)

pid = spawn('/bin/bummer', ['bummer', '-ever', 'summer'], posix.environ)
Jul 18 '05 #3

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

10
17531
by: Jochen Hub | last post by:
Hi, I am a real beginner in Python and I was wondering if there is a way to convert a string (which contains a list) to a "real" list. I need this since I would like to give a list as an argument to my Python script from the bash: #!/usr/bin/python import sys
20
2235
by: Lucas Raab | last post by:
I'm done porting the C code, but now when running the script I continually run into problems with lists. I tried appending and extending the lists, but with no avail. Any help is much appreciated Please see both the Python and C code at http://home.earthlink.net/~lvraab. The two files are ENIGMA.C and engima.py TIA
41
3958
by: Odd-R. | last post by:
I have to lists, A and B, that may, or may not be equal. If they are not identical, I want the output to be three new lists, X,Y and Z where X has all the elements that are in A, but not in B, and Y contains all the elements that are B but not in A. Z will then have the elements that are in both A and B. One way of doing this is of course to iterate throug the lists and compare each of the element, but is there a more efficient way? ...
7
8395
by: Majnu | last post by:
Hi community, just in case somebody needs a shellsort in c#, I rewrote the pascal code that I found in another newsgroup. Here are both. For more explanation on the pascal code you can search for the post on google. I was interested in the shell sort because I needed to sort long lists of data that may already be in order. For that reason I didn't want to use the arraylist's sort method, which uses quick sort (and has a worst case for...
8
2155
by: BARTKO, Zoltán | last post by:
Hello, folks, I am trying to install pgsql8 on winxp. I tried first to install "as is" with pginstaller beta2-dev3, no luck, it froze, switched off Nod32, froze a little later, ran through the list of services, switched off anything that seemed to be a firewall, no luck. So I compiled beta3 with mingw, installed, and now initdb keeps telling me this:
2
8797
by: V_S_H_Satish | last post by:
Dear Friends I am working as oracle and ms sql dba from last 4 years. My company recently migrated to DB2 databases. So i am very much new to db2 database Can any one pls provide script to do daily db2 check lists. The following colums i need in the daily check lists
8
5635
by: Mir Nazim | last post by:
Hello, I need to write scripts in which I need to generate all posible unique combinations of an integer list. Lists are a minimum 12 elements in size with very large number of possible combination(12!) I hacked a few lines of code and tried a few things from Python CookBook (http://aspn.activestate.com/ASPN/Cookbook/), but they are hell slow.
10
6579
by: AZRebelCowgirl73 | last post by:
This is what I have so far: My program! import java.util.*; import java.lang.*; import java.io.*; import ch06.lists.*; public class UIandDB {
19
1978
RMWChaos
by: RMWChaos | last post by:
Previously, I had used independent JSON lists in my code, where the lists were part of separate scripts. Because this method did not support reuse of a script without modification, I decided to consolidate all my JSON lists into one and modify my scripts so that they were more generic and reusable. So far so good. The problem is that my JSON lists used variables for many pieces of code that performed multiple iterations to create several...
0
8984
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However, people are often confused as to whether an ONU can Work As a Router. In this blog post, we’ll explore What is ONU, What Is Router, ONU & Router’s main usage, and What is the difference between ONU and Router. Let’s take a closer look ! Part I. Meaning of...
0
9530
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed. This is as boiled down as I can make it. Here is my compilation command: g++-12 -std=c++20 -Wnarrowing bit_field.cpp Here is the code in...
0
9363
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven tapestry of website design and digital marketing. It's not merely about having a website; it's about crafting an immersive digital experience that captivates audiences and drives business growth. The Art of Business Website Design Your website is...
1
9312
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows Update option using the Control Panel or Settings app; it automatically checks for updates and installs any it finds, whether you like it or not. For most users, this new feature is actually very convenient. If you want to control the update process,...
0
9238
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each protocol has its own unique characteristics and advantages, but as a user who is planning to build a smart home system, I am a bit confused by the choice of these technologies. I'm particularly interested in Zigbee because I've heard it does some...
0
8237
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing, and deployment—without human intervention. Imagine an AI that can take a project description, break it down, write the code, debug it, and then launch it, all on its own.... Now, this would greatly impact the work of software developers. The idea...
0
6073
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and then checking html paragraph one by one. At the time of converting from word file to html my equations which are in the word document file was convert into image. Globals.ThisAddIn.Application.ActiveDocument.Select();...
0
4864
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
3
2206
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence can significantly impact your brand's success. BSMN Consultancy, a leader in Website Development in Toronto offers valuable insights into creating effective websites that not only look great but also perform exceptionally well. In this comprehensive...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.