subprocess.Popen() 替代 os.system() 的问题
我正在一个有48个核心的集群上运行一个Python脚本,这个集群实际上有一个主机和三个从机。我需要生成一组文件,运行一些脚本来处理这些文件,收集结果,然后删除这些文件。接着我会重复这个过程——重新生成文件、执行脚本、删除文件等等。
当我删除并重新生成同名的文件时,我发现从机会抱怨找不到这些文件。
我通过os.system()
来运行Python脚本。
我从这篇文章了解到,使用subprocess.Popen()
比os.system
更好,因为这样可以确保我的脚本生成文件后再继续执行。我可以使用os.system("pause")
或者time.sleep(whatever)
来等待,但我想把我的os.system换成subprocess.popens或者subprocess.calls,现在卡住了。
我查阅了Python的文档,尝试了subprocess.Popen('ls')
,但我无法让像subprocess.Popen('cd /whatever_directory')
这样简单的命令正常工作。
这听起来可能有点傻,但我想知道如何通过subprocess
来执行像cd
这样的简单命令,而不是用os.system('cd')
。
然后,我实际上想把以下内容转换成subprocess。我该怎么做呢?
import os,optparse
from optparse import OptionParser
parser.add_option("-m", "--mod",dest='module', help='Enter the entity name')
parser.add_option("-f", "--folder", dest="path",help="Enter the path")
module=options.module
path=options.path
os.system('python %s/python_repeat_deckgen_remote.py -m %s' %(path,module))
我只是把os.system替换成了subprocess.Popen。
但这给了我很多错误提示:
File "/usr/lib64/python2.6/subprocess.py", line 633, in __init__
errread, errwrite)
File "/usr/lib64/python2.6/subprocess.py", line 1139, in _execute_child
raise child_exception
OSError: [Errno 2] No such file or directory
3 个回答
我可能没有直接回答你的问题,但对于需要运行子进程的任务,我总是使用 plumbum。
在我看来,这样做会让任务变得简单且更容易理解,包括在远程机器上运行。
使用 plumbum 时,如果想要设置子进程的工作目录,你可以在 with local.cwd(path): my_cmd()
的上下文中运行命令。
我无法让像
subprocess.Popen('cd /whatever_directory')
这样简单的命令正常工作。
每个进程的当前工作目录都是独立的,和系统中的其他进程没有关系。
当你启动一个子进程(使用这些方法中的任何一种),让它 cd
到另一个目录时,这对父进程没有影响,也就是对你的Python脚本没有影响。
要改变你脚本的当前工作目录,你应该使用 os.chdir()
。
正如NPE已经提到的,新创建的进程不会影响到已经存在的进程(这意味着 os.system('cd /some/where')
对当前进程也没有影响)。不过在这种情况下,我觉得你可能被一个细节绊住了,那就是 os.system
会启动一个命令行来解释你传入的命令,而 subprocess.Popen
默认情况下并不会这样做。但你可以告诉它这样做:
proc = subprocess.Popen(
'python %s/python_repeat_deckgen_remote.py -m %s' % (path, module),
shell = True)
status = proc.wait()
如果你要调用一个命令行内置的命令或者使用命令行扩展,那么就必须启动命令行(前提是你不想模拟这个过程):
>>> import subprocess
>>> x = subprocess.Popen('echo $$')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/local/lib/python2.7/subprocess.py", line 679, in __init__
errread, errwrite)
File "/usr/local/lib/python2.7/subprocess.py", line 1249, in _execute_child
raise child_exception
OSError: [Errno 2] No such file or directory
>>> x = subprocess.Popen('echo $$', shell = True); x.wait()
81628
0
>>>
不过,如果你的问题允许的话,你可以绕过命令行——这对安全性有帮助——通过把命令的参数拆分成一个列表:
>>> x = subprocess.Popen(['echo', '$$']); x.wait()
$$
0
>>>
注意这次输出的是字符串 $$
,而不是进程ID,因为这次命令行没有解释这个字符串。
比如对于你最初的例子,你可以使用:
proc = subprocess.Popen(['python',
os.path.join(path, 'python_repeat_deckgen_remote.py'),
'-m',
module])
这样可以避免如果 path
和/或 module
包含命令行特殊字符时出现的问题。
(你甚至可以考虑用 cwd = path
来调用 subprocess.Popen
,这样就可以省去调用 os.path.join
,不过这要看其他情况。)