简体   繁体   English

如何使用python子进程模块执行包含脚本的字符串

[英]How to execute a string containing a script using python subprocess module

I receive a script in a string and trying to find a way to execute it using the subprocess module of python. 我收到一个字符串脚本,并试图找到一种使用python的子进程模块执行该脚本的方法。 eg 例如

import subprocess
script = """#!/usr/bin/python
            print "inside script"
         """
subprocess.Popen(script)

This throws an OSError: saying there is no such file or directory, which is fair enough as I think its trying to look for command name. 这引发OSError:说没有这样的文件或目录,这很公平,因为我认为它试图查找命令名。

I then tried subprocess.Popen(script, shell=True) which works only for shell commands and totally ignores the #! 然后subprocess.Popen(script, shell=True)我尝试了subprocess.Popen(script, shell=True) ,它仅适用于shell命令,完全忽略了#! at the top of the script. 在脚本的顶部。 Is there any way to make suprocess run my script stored in string like its an executable file ? 有什么办法可以让suprocess运行以字符串形式存储的脚本(例如其可执行​​文件)?

As you can read in the Popen Python Documentation the parameter to Popen is an executable to launch, not the contents of some script to perform. 正如你在读POPEN Python文档的参数Popen是一个可执行文件来启动,而不是一些脚本的内容来执行。 You cannot use Popen in this manner. 您不能以这种方式使用Popen

If you really want to you could write the script to a file and then pass that filename to Popen, but that doesn't seem to be an elegant solution to whatever your problem is. 如果确实需要,可以将脚本写入文件,然后将该文件名传递给Popen,但这对于您遇到的任何问题似乎都不是一个很好的解决方案。

Seeing as all you want is simply to execute some Python code from a string, you'll want to use the exec builtin function 看起来您只需要从字符串中执行一些Python代码,就可以使用exec内置函数

This solution is based on -c (compile) Python interpreter cmdline argument. 此解决方案基于-c (编译)Python解释器cmdline参数。 It ignores using shell properties entirely. 它完全忽略了使用shell属性。

Popen may be created in similar way. Popen可以以类似方式创建。 subprocess.call was used to show that script is in fact executed, and python interpreter return code is changed by code executed. subprocess.call用于显示脚本实际上已执行,并且python解释器的返回代码已由执行的代码更改。

import subprocess

executable_code = """
print 'inside script'
print 123
"""

code_with_exception = """
raise Exception()
"""

ok_rc = subprocess.call(['python', '-c', executable_code])
assert ok_rc == 0

bad_rc = subprocess.call(['python', '-c', code_with_exception])
assert bad_rc == 1

Additional improvement would be to skip 'python' hardcoded string and use sys.executable . 进一步的改进是跳过“ python”硬编码字符串并使用sys.executable

A string giving the absolute path of the executable binary for the Python interpreter, on systems where this makes sense. 一个字符串,给出有意义的系统上Python解释器的可执行二进制文件的绝对路径。 If Python is unable to retrieve the real path to its executable, sys.executable will be an empty string or None. 如果Python无法检索其可执行文件的真实路径,则sys.executable将为空字符串或无。

import sys
import subprocesss
code = "raise Exception()"
bad_rc = subprocess.call([sys.executable, '-c', code])
assert bad_rc == 1

You can run scripts by pumping them into a child python's stdin . 您可以通过将脚本泵入子python的stdin来运行脚本。 This may be a preferred solution to larger scripts: 对于较大的脚本,这可能是首选的解决方案:

import sys
import subprocess as subp
import shutil

script = """\
import sys
print "hello", sys.argv
"""

p = subp.Popen([sys.executable, '-', 'arg1', 'arg2'], stdin=subp.PIPE)
p.stdin.write(script)
p.stdin.close()
p.wait()

I use this trick across ssh connections to control remote servers. 我在ssh连接中使用此技巧来控制远程服务器。

To execute a string as a Python script using subprocess module: 要使用subprocess模块将字符串作为Python脚本执行:

>>> import subprocess, sys, textwrap
>>> subprocess.call(textwrap.dedent('''
...    print "Hello, world!"
... '''), shell=True, executable=sys.executable)
Hello, world!
0

Though as @wich suggested you could use Python builtin function exec() -- it is a statement on Python 2: 尽管正如@wich所建议的那样,您可以使用Python内置函数exec() -这是关于Python 2的声明:

>>> exec 'print "Hello, exec!"'
Hello, exec!

If you want to run Python code in a different process, you could use multiprocessing or concurrent.futures modules : 如果要在其他过程中运行Python代码,则可以使用multiprocessingconcurrent.futures模块

#!/urs/bin/env python2
from multiprocessing import Process, freeze_support

def run(code):
    exec code # Python 2

if __name__ == "__main__":
    freeze_support()
    Process(target=run, args=['print "Hello, multiprocessing"']).start()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM