How to get a variable from the shell in python?

2019-08-10 11:49发布

I'm writing a script that needs to take advantage of a Java daemon via the local dbus of the linux machines it will run on. This daemon in particular will return an array of tuples which I want so that I can parse through/use the information in later in my code. I want this code to take this value from multiple machines at once, but the problem is the only way I see to really take return/exit values from a terminal which I am ssh'ed into is by parsing stdout's output. I don't want to do this, I'd much prefer to get the actual variable. Right now I have this:

import os
message = "import dbus, sys\nbus=dbus.SystemBus()\nremote_object=bus.get_object('daemon.location', '/daemon')\ncontroller=dbus.Interface(remote_object, 'daemon.path')\nsys.exit(controller.getValue())"
x = os.system('echo \-e "%s" \| ssh %s python' %(message, ip))

In this example when I run "controller.getValue()" it returns an array of tuples. I'm trying to figure out a way to get that array. When using something like popen it pipes the output in stdout into a file and returns it to you, that way you get a string equivalent of the array. What I'm trying to figure out is how to get the actual array. As if to pass the variable returned when exiting the ssh tty into my code. Any ideas?

3条回答
干净又极端
2楼-- · 2019-08-10 12:19

Why not use popen?

lines = os.popen("your command here").readlines()
查看更多
别忘想泡老子
3楼-- · 2019-08-10 12:24

You can't avoid serialization if there is no shared memory. There are only bytes on the wire. You could use a library that hides it from you e.g., with execnet module:

#!/usr/bin/env python
import execnet

gw = execnet.makegateway("ssh=user@host")
channel = gw.remote_exec("""
import dbus, sys

bus = dbus.SystemBus()
remote_object = bus.get_object('daemon.location', '/daemon')
controller = dbus.Interface(remote_object, 'daemon.path')

channel.send(controller.getValue())
""")
tuple_ = channel.receive()
print tuple_
print tuple_[0]

But it easy to parse simple tuple values yourself using ast.literal_eval() from stdlib:

#fabfile.py
import ast
from fabric.api import run

def getcontroller():
    """Return controller value."""
    cmd = """
import dbus, sys

bus = dbus.SystemBus()
remote_object = bus.get_object('daemon.location', '/daemon')
controller = dbus.Interface(remote_object, 'daemon.path')

print repr(controller.getValue())
""" #NOTE: you must escape all quotation marks
    output = run('python -c "%s"' % cmd)
    tuple_ = ast.literal_eval(output)
    print tuple_[0]

Example: $ fab getcontroller -H user@host

Here I've used fabric to run the command on remote host.

You could use JSON as a serialization format if the other end doesn't produce Python literals:

>>> import json
>>> t = (1, "a")
>>> json.dumps(t)
'[1, "a"]'
>>> json.loads(_)
[1, u'a']
>>>
查看更多
冷血范
4楼-- · 2019-08-10 12:25

If you just want a shell variable then you could do this

$ FOO="myFOO"
$ export FOO
$ cat x.py
#!/usr/bin/python
import os
print os.environ['FOO']
$ ./x.py
myFOO
$ 

If you want the return code of a program:

try:
    retcode = call("mycmd" + " myarg", shell=True)
    if retcode < 0:
        print >>sys.stderr, "Child was terminated by signal", -retcode
    else:
        print >>sys.stderr, "Child returned", retcode
except OSError, e:
    print >>sys.stderr, "Execution failed:", e

If you could probably explain you requirement a little better, you might get better help

查看更多
登录 后发表回答