views:

1367

answers:

3

I am building an application plugin in Python which allows users to arbitrarily extend the application with simple scripts (working under Mac OS X). Executing Python scripts is easy, but some users are more comfortable with languages like Ruby.

From what I've read, I can easily execute Ruby scripts (or other arbitrary shell scripts) using subprocess and capture their output with a pipe; that's not a problem, and there's lots of examples online. However, I need to provide the script with multiple variables (say a chunk of text along with some simple boolean information about the text the script is modifying) and I'm having trouble figuring out the best way to do this.

Does anyone have a suggestion for the best way to accomplish this? My goal is to provide scripts with the information they need with the least required code needed for accessing that information within the script.

Thanks in advance!

+3  A: 

See http://docs.python.org/library/subprocess.html#using-the-subprocess-module

args should be a string, or a sequence of program arguments. The program to execute is normally the first item in the args sequence or the string if a string is given, but can be explicitly set by using the executable argument.

So, your call can look like this

p = subprocess.Popen( args=["script.sh", "-p", p_opt, "-v", v_opt, arg1, arg2] )

You've put arbitrary Python values into the args of subprocess.Popen.

S.Lott
I'd found that myself, but that doesn't seem very friendly for the script, since it then has to parse through commandline arguments if it wants the data. If there aren't any better options, I'll go with this, though. Thanks!
One Crayon
What? What does this mean? "since it [the script] then has to parse through commandline arguments" That's what scripts do. Please update your question to explain what your concern or problem is.
S.Lott
I need to find the way to get variables from my Python code into the non-Python scripts that takes the least amount of code in the non-Python scripts. The scripts will be authored by others, and the fewer requirements there are, the more likely they'll be to write them.
One Crayon
The command-line interface is very clumsy. Sorry for it being defined that way, but the command-line shell interface was defined by POSIX standards and unix before that. It cannot be changed.
S.Lott
+1  A: 

If you are going to be launching multiple scripts and need to pass the same information to each of them, you might consider using the environment (warning, I don't know Python, so the following code most likely sucks):

#!/usr/bin/python 

import os

try:
    #if environment is set
    if os.environ["child"] == "1":
     print os.environ["string"]
except:
    #set environment
    os.environ["child"]  = "1"
    os.environ["string"] = "hello world"

    #run this program 5 times as a child process
    for n in range(1, 5):
     os.system(__file__)
Chas. Owens
A: 

One approach you could take would be to use json as a protocol between parent and child scripts, since json support is readily available in many languages, and is fairly expressive. You could also use a pipe to send an arbitrary amount of data down to the child process, assuming your requirements allow you to have the child scripts read from standard input. For example, the parent could do something like (Python 2.6 shown):

#!/usr/bin/env python

import json
import subprocess

data_for_child = {
    'text' : 'Twas brillig...',
    'flag1' : False,
    'flag2' : True
}

child = subprocess.Popen(["./childscript"], stdin=subprocess.PIPE)
json.dump(data_for_child, child.stdin)

And here is a sketch of a child script:

#!/usr/bin/env python
# Imagine this were written in a different language.

import json
import sys

d = json.load(sys.stdin)
print d

In this trivial example, the output is:

$ ./foo12.py
{u'text': u'Twas brillig...', u'flag2': True, u'flag1': False}
Jacob Gabrielson