【问题标题】:Issues with subprocess.Popen() replacing os.system()subprocess.Popen() 替换 os.system() 的问题
【发布时间】:2013-03-23 06:54:09
【问题描述】:

我试图通过一个 48 核集群上的 python 脚本生成一组文件,该集群实际上有一个主机器和 3 个从机器。我需要生成一组文件,在它们上运行一些脚本,收集结果然后删除它们。我再次重复这个过程——重新生成文件、执行、删除等, 当我删除并重新生成同名文件时,我看到从机抱怨它找不到文件。 我正在通过os.system()运行python脚本

我从this post 了解到,最好使用subprocess.Popen() 而不是os.system,这样它实际上会等待我的脚本生成我的文件,然后再继续执行。我可以使用 os.system("pause")time.sleep(whatever) 等待,但我想将我的 os.systems 转换为 subprocess.popens 或 subprocess.calls 并且我被困在这里。

我浏览了 python 文档并尝试了 subprocess.Popen('ls'),但我无法让像 subprocess.Popen('cd /whatever_directory') 这样简单的东西正常工作。

这听起来可能很傻,但是我如何执行像cdsubprocess 这样一个简单的命令,而不是os.system('cd')

然后,我实际上想将以下内容转换为子流程。我该怎么做?

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))

我刚刚用 subprocess.Popen 替换了 os.system。 但它给了我很多抱怨:

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

【问题讨论】:

    标签: python subprocess


    【解决方案1】:

    正如 NPE 已经指出的,新进程不会影响现有进程(这意味着 os.system('cd /some/where') 也不会影响当前进程)。不过,在这种情况下,我认为您会因为 os.system 调用 shell 来解释您传入的命令而绊倒,而 subprocess.Popen 默认情况下不这样做。但你可以告诉它这样做:

    proc = subprocess.Popen(
        'python %s/python_repeat_deckgen_remote.py -m %s' % (path, module),
        shell = True)
    status = proc.wait()
    

    如果您正在调用 shell 内置命令或使用 shell 扩展,则有必要调用 shell(假设您不愿意模拟它):

    >>> 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
    >>> 
    

    但是如果您的问题允许,您可以通过将命令参数分解为一个列表来绕过 shell(这有助于解决安全问题):

    >>> x = subprocess.Popen(['echo', '$$']); x.wait()
    $$
    0
    >>>
    

    注意这次这里的输出是字符串$$,而不是进程ID,因为这一次shell没有解释这个字符串。

    例如,对于您的原始示例,您可以使用:

    proc = subprocess.Popen(['python',
        os.path.join(path, 'python_repeat_deckgen_remote.py'),
        '-m',
        module])
    

    这可以避免path 和/或module 包含shell 特殊字符时出现的问题。

    (您甚至可能想用cwd = path 调用subprocess.Popen 并消除对os.path.join 的调用,尽管这取决于其他事情。)

    【讨论】:

      【解决方案2】:

      我无法让像 subprocess.Popen('cd /whatever_directory') 这样简单的东西正常工作。

      每个进程的当前工作目录独立于系统中的其他进程。

      当您启动一个子进程(使用这两种机制中的任何一种),并将其带到 cd 到另一个目录时,这对父进程没有影响,即对您的 Python 脚本。

      要更改脚本的当前工作目录,您应该使用os.chdir()

      【讨论】:

      • 我知道我可以使用 os.chdir()。但我的问题是——我想使用子进程而不是 os.system 来运行命令。我使用的一个示例是: os.system('cd') 有效,其中 'cd' 是我所指的命令。那么,在这种情况下如何用子进程替换 os.system 。同样,我使用 os.system('python *.py) 运行了 python 命令。我想用子进程替换 os.system,我该怎么做?
      【解决方案3】:

      我可能不会直接回答你的问题,但是对于需要运行子进程的此类任务,我总是使用plumbum

      IMO,它使任务更加简单和直观,包括在远程机器上运行。

      使用plumbum,为了设置子进程的工作目录,你可以在with local.cwd(path): my_cmd()上下文中运行命令。

      【讨论】:

        猜你喜欢
        • 2018-04-30
        • 2011-06-16
        • 2013-03-09
        • 2015-05-20
        • 1970-01-01
        • 2011-08-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多