Maven命令mvn从终端运行没有错误,但从python没有错误

Bek*_*aro 5 java shell subprocess maven python-3.x

我正在尝试从 python 脚本运行 Maven 项目。我已经安装了 apache maven。运行命令:mvn exec:java -D"exec.mainClass"="org.matsim.project.RunMatsim"从终端在 pom.xml 所在的项目文件夹中,不会产生错误并且项目运行正常。

但是当从我的 python 脚本运行以下代码时

import subprocess as sp

def execute(cmd):
    popen = sp.Popen(cmd, stdout=sp.PIPE, universal_newlines=True,shell=True)
    for stdout_line in iter(popen.stdout.readline, ""):
        yield stdout_line 
    popen.stdout.close()
    return_code = popen.wait()
    if return_code:
        raise sp.CalledProcessError(return_code, cmd)

for path in execute(["mvn", "exec:java" ,'-D"exec.mainClass"="org.matsim.project.MatsimRun"']):
    print(path, end="")
Run Code Online (Sandbox Code Playgroud)

我收到以下错误:

[错误] 没有为此构建指定目标。您必须以 : 或 :[:]: 格式指定有效的生命周期阶段或目标。可用的生命周期阶段有:验证、初始化、生成源、处理源、生成资源、处理资源、编译、处理类、生成测试源、处理测试源、生成测试资源、处理-test-resources, test-compile, process-test-classes, test, prepare-package, package, pre-integration-test, integration-test, post-integration-test, verify`

为什么会这样?可能有什么问题?

两种情况(终端、python 脚本)发生的警告相同。

PiR*_*cks 5

通常,当我在从 java/python/etc 运行程序时遇到 args 问题时。我将要使用的命令包装在 中sh -c,如下所示:

sp.Popen(['/bin/sh', '-c', "mvn exec:java -D\"exec.mainClass\"=\"org.matsim.project.MatsimRun\""])
Run Code Online (Sandbox Code Playgroud)

以上似乎对我来说正常工作。请注意这样做可能会带来安全隐患,请确保作为第三个参数输入的命令sh永远不会连接到仇恨互联网。

好的,现在为什么您的代码不起作用?

python文档说这shell=True相当于:

Popen(['/bin/sh', '-c', args[0], args[1], ...])
Run Code Online (Sandbox Code Playgroud)

所以一个好的假设是sh忽略arg[1]和进一步论​​证。您可以通过执行以下操作来测试:

<censored>@debian:~$ sh -c echo "sfaklg"

<censored>@debian:~$ 
Run Code Online (Sandbox Code Playgroud)

观察如何echo没有得到它期望的参数。这在许多不同的引用方法/shell 中是一致的:

<censored>@debian:~$ dash -c echo "sfaklg"

<censored>@debian:~$ bash -c echo "sfaklg"

<censored>@debian:~$ zsh -c echo "sfaklg"

<censored>@debian:~$ zsh -c echo sfaklg

<censored>@debian:~$ bash -c echo sfaklg

<censored>@debian:~$ 

Run Code Online (Sandbox Code Playgroud)

bash 的手册页说:

如果存在 -c 选项,则从第一个非选项参数 command_string 中读取命令。如果 command_string 之后有参数,则第一个参数将分配给 $0,其余参数分配给位置参数。对 $0 的赋值设置了 shell 的名称,该名称用于警告和错误消息。

换句话说sh -c,用于运行期望 args 与$1, $2, ...一起传递的 shell 脚本。

那你该怎么办?

怀疑您想在 shell 中运行 maven,因为它需要设置JAVA_HOME或类似的环境变量。这个问题给出了如何设置/修改环境变量的例子,尽管你可能仍然需要shell=True. 这个答案还建议使用 env 命令来覆盖环境变量。

最后,您可能会发现这个问题很有帮助。