我想从python脚本中调用一个单独的非子python程序,并让它在新的shell实例中运行。原始的python脚本不需要知道它启动的实例,它不应该在启动的进程运行时阻塞,并且不应该关心它是否死亡。这是我试过的,它没有返回任何错误,但似乎什么都不做......
import subprocess
python_path = '/usr/bin/python'
args = [python_path, '&']
p = subprocess.Popen(args, shell=True)
我应该做些什么不同
这样做的原因是我有一个内置版本的python的应用程序,我已经写了一些python工具,应该与这个应用程序一起单独运行,但不能保证用户将在他们的系统上安装python在我正在使用的内置版本的应用程序之外。因此,我可以以编程方式从内置版本获取python二进制路径,并且我想启动内置python的外部版本。这消除了用户自己安装python的需要。所以本质上我需要一种简单的方法来以编程方式使用我当前运行的python版本来调用外部python脚本。
我不需要将任何输出捕获到原始程序中,实际上一旦启动我就不喜欢它与原始程序无关
所以我的原始问题似乎很不清楚所以这里有更多细节,我想我试图简化这个问题:
我正在运行OSX,但代码也适用于Windows机器。
具有内置CPython版本的主应用程序是一个已编译的c ++应用程序,它附带了一个在运行时使用的python框架。您可以在OSX上的终端窗口中执行此版本的python的嵌入式版本
/my_main_app/Contents/Frameworks/Python.framework/Versions/2.7/bin/python
从我的主应用程序中,我希望能够在主应用程序中嵌入的python版本中运行命令,该命令使用上面的python版本启动python脚本的外部副本,就像我做的那样在终端窗口中执行以下命令。新启动的孤立进程应该有自己的终端窗口,以便用户可以与它进行交互。
/my_main_app/Contents/Frameworks/Python.framework/Versions/2.7/bin/python my_python_script
我希望子python实例不阻止主应用程序,我希望它有自己的终端窗口,以便用户可以与它进行交互。一旦孩子以任何方式启动,主要应用程序不需要知道孩子。我这样做的唯一原因是使用终端为用户自动启动外部应用程序
答案 0 :(得分:2)
如果您正在尝试启动新的终端窗口以运行新的Python(这不是您的问题所要求的,但是从评论中听起来就像您真正想要的那样):
你做不到。至少不是通用的跨平台方式。
Python只是一个命令行程序,可以使用给定的stdin / stdout / stderr运行。如果那些碰巧来自终端,那么它正在终端中运行。除此之外,它对终端一无所知。
如果你需要为某个特定平台和一些特定的终端程序执行此操作 - 例如OS X上的Terminal.app,OS X上的iTerm,Windows上的“DOS提示符”,任何X11系统上的gnome-terminal等 - 这通常是可行的,但是这样做的方法是启动或编写终端程序并告诉它打开一个新窗口并在该窗口中运行Python。而且,不用说,他们都有完全不同的方式。
即便如此,在所有情况下都不可能。例如,如果您在远程计算机上运行并在该计算机上运行Python,则无法返回到您的计算机并打开新的终端窗口。
在大多数具有多个可能终端的平台上,您可以编写一些启发式代码,通过步行os.getppid()
找出您当前正在运行的终端,直到找到看起来像您知道如何的终端的内容处理(如果你到达init
/ launchd
/等没有找到,那么你就没有在终端中运行。)
答案 1 :(得分:0)
问题是您使用参数&
运行Python。 Python不知道如何处理它。就像在shell上输入一样:
/usr/bin/python '&'
事实上,如果你注意,你几乎肯定会通过你的stderr获得这样的东西:
python: can't open file '&': [Errno 2] No such file or directory
......这正是你在shell上做同等事情所得到的。
您可能想要的是此 shell命令:
/usr/bin/python &
但是&
根本没有参数,它是sh语法的一部分。 subprocess
模块对sh语法一无所知,你告诉它不要使用shell,所以没有人能解释&
。
您可以告诉subprocess
使用shell,因此它可以为您执行此操作:
cmdline = '{} &'.format(python_path)
p = subprocess.Popen(cmdline, shell=True)
但实际上,没有充分的理由。只需打开子流程而不是在其上调用communicate
或wait
已经有效地“将其置于后台”,就像&
在shell上一样。所以:
args = [python_path]
p = subprocess.Popen(args)
这将启动一个新的Python解释器,它位于后台运行,尝试使用与父级相同的stdin / stdout / stderr。我不确定你为什么要这样,但是在shell中使用&
也是如此。
答案 2 :(得分:0)
实际上我认为你的问题可能有一个解决方案,我在另一个问题here找到了一个有用的解决方案。 这样subprocess.popen启动一个新的python shell实例并从那里运行第二个脚本。它在Windows 10上对我很有用。
答案 3 :(得分:0)
您可以尝试使用screen命令
使用此命令创建一个新的shell实例,当前实例在后台运行。
# screen; python script1.py
运行上面的命令后,会看到一个新的shell提示符,我们可以在那里运行另一个脚本,script1.py将在后台运行。
希望它有所帮助。