在子进程中,某些命令有效,但来自 Mac 终端的其他命令无效

In subprocess, some commands work but not others from Mac terminal

我正在尝试创建一个 python 脚本,它在 Mac 终端上运行一个 perl 脚本。流行的 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'

这个returns:

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 语法是正确的,因为如果我直接在终端中输入它,它就可以完美运行。有人能看出我做错了什么吗?

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 should be a sequence of program arguments or else a single string. By default, the program to execute is the first item in args if args is a sequence. If args is a string, the interpretation is platform-dependent and described below. See the shell and executable arguments for additional differences from the default behavior. Unless otherwise stated, it is recommended to pass args as a sequence.

(强调我的)

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")。这将打开一个 shell,更改目录 在那个 shell,然后退出。您的 Python 脚本仍将在原始工作目录中运行。要更改它,请改用 os.chdir("Slic3r")。 (参见 here。)

你也可以使用 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

接受的方式拆分它们