【问题标题】:subprocess module works but not exactly working子流程模块工作但不完全工作
【发布时间】:2014-08-25 07:29:28
【问题描述】:

我正在尝试将os.system 替换为子进程模块(引用自here),但是虽然它似乎可以工作(在脚本编辑器中显示结果)但实际上并没有工作。

def convert_text(inImg, outImg, texImg):
    if not os.path.exists(texImg):
        Image.open(inImg).save(outImg)
        #os.system('/apps/Linux64/prman-18.0/bin/txmake ' + outImg + ' ' + texImg)
        subprocess.Popen("/apps/Linux64/prman-18.0/bin/txmake" + outImg + " " + texImg, shell = True)
        os.remove(outImg)
        print "Done converting " + inImg

上面的代码应该查找任何图像文件,将其转换为 .tif,然后是 .tex。虽然结果可能会显示Done converting /user_data/texture/testTexture_01.tga,但实际上在目录中找不到任何 .tex 文件。 (应该有 .tex 文件位于 /user_data/texture,即图像文件所在的位置)

我也尝试将其写为subprocess.Popen('/apps/Linux64/prman-18.0/bin/txmake %s %s'% (outImg, texImg), shell = True),但它不起作用。

编辑:我在 Maya 中运行以下代码,因为我正在该软件中实现该代码

我在某些方面做错了吗?

【问题讨论】:

  • @suhail 我没有看到任何错误,即使我在 Maya 中使用 echo all commands 时已打开它

标签: python subprocess maya


【解决方案1】:

subprocess.Popen 接受参数列表。即尝试:

subprocess.Popen(["/apps/Linux64/prman-18.0/bin/txmake", outImg, texImg])

更新:删除shell=True

【讨论】:

  • 如果您的文件名中可能包含空格、引号、星号等,请不要使用shell = True。基本上,在您真正知道自己在做什么之前,不要使用shell = True。这是错误和安全漏洞的常见来源。
  • @suhall 它似乎对我也不起作用
  • 如果您使用shell=True,您应该将命令作为字符串而不是列表传递。但是,您通常不应使用 shell=True,如前所述。
【解决方案2】:

Popen 是非阻塞的,所以调用返回时它实际上并不完整。因为您在Popen 调用开始后立即删除outImg,所以该命令可能会失败。改用subprocess.call,它将阻塞直到命令完成:

subprocess.call(["/apps/Linux64/prman-18.0/bin/txmake", outImg, texImg]) 

【讨论】:

  • 酷,它有效!顺便问一下,os.remove 也有一个子进程吗?
  • @dissidia os.remove 是用于文件删除的正确方法。一般来说,你应该只在标准库中没有本地方法的情况下使用subprocess 模块来做某事。
  • 对缺乏理解深表歉意。只是想如果os.system 有一个子进程模块,我认为os.remove 也会有一个,毕竟他们正在共享os 模块,你看......但是我能问你后一句话的意思吗- when there's no native method in the standard library?
  • @dissidia subprocess 模块旨在替代用于在 Python 中运行子进程的所有其他方法和模块(示例包括 os.systemos.popenos.spawn*commands 模块)。 os.remove 可以删除文件而根本不需要启动子进程。启动子流程有很多开销,因此您应该始终更喜欢使用不涉及这样做的方法(如果它们可用)(这就是我所说的“本机”)。
【解决方案3】:

正如@suhail 所说,Popen 接受参数列表,但(截至目前)他的示例代码是错误的。它应该是这样的:

#os.system('/apps/Linux64/prman-18.0/bin/txmake ' + outImg + ' ' + texImg)
subprocess.Popen(["/apps/Linux64/prman-18.0/bin/txmake", outImg, texImg])

您应该使用shell = True,除非您已验证 outImg 和 texImg 没有对 shell 具有特殊意义的字符(引号、空格、星号、等)在他们。使用shell = True,这些字符将由shell 处理,结果可能不是您所期望的。你想要的是shell = False(这是默认值),这样带有引号、空格等的文件名将在传递给 shell 之前正确地进行反斜杠转义。

更新:您可能想使用subprocess.call(),而不是subprocess.Popen()。请参阅the subprocess module documentationcall() 将等待命令完成,然后返回整数返回码(如果没有发生错误,则返回 0)。您应该捕获该返回代码并对其进行测试,然后仅在没有错误的情况下删除outImg。例如:

def convert_text(inImg, outImg, texImg):
    if not os.path.exists(texImg):
        Image.open(inImg).save(outImg)
        #os.system('/apps/Linux64/prman-18.0/bin/txmake ' + outImg + ' ' + texImg)
        retcode = subprocess.call("/apps/Linux64/prman-18.0/bin/txmake", outImg, texImg)
        if (retcode == 0):
            os.remove(outImg)
        else:
            print "txmake returned error code " + str(retcode)
        print "Done converting " + inImg

阅读文档,了解更多关于 call() 可以做什么的详细信息。

【讨论】:

  • 它似乎不起作用,还是我应该使用其他命令?
  • @dissidia - 抱歉,我应该推荐subprocess.call() 而不是Popen()。如果您想说“只需运行此外部程序并在完成后返回给我”,这就是您的代码所需要的功能。
  • 我有一个问题,比如Popencall 之间到底有什么区别?我怎么知道何时使用它?
  • @dissidia - 如果您想详细了解差异,请阅读文档;我只能笼统地介绍一下。基本上,call 在返回之前等待进程运行; Popen 启动外部进程,然后在进程仍在运行时立即返回,返回一个Popen object,让您可以与外部进程交互(将数据发送到其标准输入、读取其标准输出或标准错误等)。因此,如果您需要启动该过程并且什么都不做,请使用call。如果需要与之交互,请使用Popen
猜你喜欢
  • 2010-12-08
  • 2012-03-13
  • 1970-01-01
  • 2011-08-19
  • 2022-12-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多