【问题标题】:In subprocess, some commands work but not others from Mac terminal在子进程中,某些命令有效,但 Mac 终端中的其他命令无效
【发布时间】:2018-06-09 03:56:36
【问题描述】:

我正在尝试创建一个在 Mac 终端上运行 perl 脚本的 python 脚本。流行的 3D 打印机切片引擎 Slic3r 具有使用命令行的能力,它是用 Perl 编写的。我想编写一个 python 脚本来自动化一些过程,这是我最了解的语言。如果我直接在终端中输入我想使用的命令,它会正常工作,但是,如果我尝试使用 python 的subprocess,它适用于某些命令,但不适用于其他命令。

例如,如果我使用我的脚本使用docs 中概述的语法来获取 Slic3r 版本,它可以正常工作。该脚本有效:

import os
import subprocess

os.system("cd Slic3r")

perl = "perl"
perl_script = "/Users/path/to/Slic3r/slic3r.pl"
params = "--version"

pl_script = subprocess.Popen([perl, perl_script, params], stdout=sys.stdout)
pl_script.communicate()

print 'done'

这会返回:

1.3.0-dev
done

如果我使用我得到的相同脚本使用诸如 --info 之类的命令(有关更多信息,请参阅修复模型下的 Slic3r 文档):

在:

import os
import subprocess

os.system("cd Slic3r")

perl = "perl"
perl_script = "/Users/path/to/Slic3r/slic3r.pl"
params = "--info /Users/path/to/Desktop/STL_Files/GEAR.stl"

pl_script = subprocess.Popen([perl, perl_script, params], stdout=sys.stdout)
pl_script.communicate()

print 'done'

输出:

Unknown option: info /Users/path/to/Desktop/STL_Files/GEAR.stl
Slic3r 1.3.0-dev is a STL-to-GCODE translator for RepRap 3D printers
written by Alessandro Ranellucci <aar@cpan.org> - http://slic3r.org/

Usage: slic3r.pl [ OPTIONS ] [ file.stl ] [ file2.stl ] ...

根据我的研究,我怀疑将字符串的空格用作参数存在一些问题。在尝试这个项目之前,我从未使用过subprocess,因此可能会出现简单的语法错误。

我知道 Slic3r 语法是正确的,因为如果我直接在终端中输入它,它就可以完美运行。谁能看到我做错了什么?

【问题讨论】:

  • 您正在执行相当于 shell 命令 'perl' 'slic3r.pl' '--info GEAR.stl' 而不是 'perl' 'slic3r.pl' '--info' 'GEAR.stl'

标签: python macos subprocess popen


【解决方案1】:

subprocess.Popen 接受args 作为第一个参数。这可以是带有完整命令(包括参数)的字符串

args = "perl /Users/path/to/Slic3r/slic3r.pl --info /Users/path/to/Desktop/STL_Files/GEAR.stl"
pl_script = subprocess.Popen(args, stdout=sys.stdout)

或列表由实际命令及其所有参数组成(您的实际命令为perl):

args = ["perl", 
        "/Users/path/to/Slic3r/slic3r.pl", 
        "--info", 
        "/Users/path/to/Desktop/STL_Files/GEAR.stl"]
pl_script = subprocess.Popen(args, stdout=sys.stdout)

首选后者,因为它绕过了shell,直接执行perl。来自文档:

args 应该是一系列程序参数,或者是单个 细绳。默认情况下,要执行的程序是args中的第一项 如果args 是一个序列。如果args 是字符串,则解释为 平台相关,如下所述。查看 shell 和可执行文件 与默认行为的其他差异的参数。除非 否则,建议将args作为序列传递

(强调我的)

args 列表当然可以使用 Python 的标准列表操作来构建:

base_args = ["perl", 
             "/Users/path/to/Slic3r/slic3r.pl"]
options   = ["--info", 
             "/Users/path/to/Desktop/STL_Files/GEAR.stl"]
args = base_args + options
args.append("--verbose")
pl_script = subprocess.Popen(args, stdout=sys.stdout)

旁注:你写了os.system("cd Slic3r")。这将打开一个外壳,更改该外壳中的目录,然后退出。您的 Python 脚本仍将在原始工作目录中运行。要更改它,请改用os.chdir("Slic3r")。 (见here。)

【讨论】:

  • 这非常有效!谢谢!另一个问题是:由于 args 是一个列表,如果我想添加、修改等,是否可以使用标准列表修饰符(如 append)而不会弄乱格式?
  • @paperstsoap 当然。 args 只是一个列表。您可以使用标准列表操作对其进行修改。只要确保第一个元素是perl,第二个是你的脚本。我已经修改了答案。
【解决方案2】:

你也可以使用 shlex 来分解复杂的参数,特别是在 mac 或 unix 中

更多信息在这里 https://docs.python.org/2/library/shlex.html#shlex.split

例如

import shlex, subprocess
args = "perl /Users/path/to/Slic3r/slic3r.pl --info /Users/path/to/Desktop/STL_Files/GEAR.stl"

#using shlex to break down the arguments 

mac_arg=shlex.split(args)

#shlex.split will return all the arguments in a list

输出

['perl', '/Users/path/to/Slic3r/slic3r.pl', '--info', '/Users/path/to/Desktop/STL_Files/GEAR.stl']

这可以进一步与 Popen 一起使用

p1=Popen(mac_arg)

Shlex 主要优点是你不需要担心命令,它总是会以 Popen 接受的方式拆分它们

【讨论】:

    猜你喜欢
    • 2013-12-28
    • 1970-01-01
    • 2019-07-30
    • 1970-01-01
    • 2021-07-18
    • 2019-05-07
    • 2021-02-20
    • 2021-10-11
    • 1970-01-01
    相关资源
    最近更新 更多