subprocess.call()在Mac和Linux上失败

2 投票
2 回答
5001 浏览
提问于 2025-04-18 04:01

我遇到了一个奇怪的问题,跟subprocess.call()这个函数有关。我想用这个函数来执行Java的'jar'命令。以下是我的代码:

import os
import subprocess
def read_war():
    war_file_path = "jackrabbit-webapp-2.6.5.war"
    java_home = os.environ['JAVA_HOME']
    jar_path = os.path.join(java_home, 'bin', 'jar')
    jar_cmd = jar_path + ' tvf ' + war_file_path
    print "command to be executed is : " + jar_cmd
    subprocess.call(jar_cmd)
read_war()

我在Windows和Linux(Oracle企业版Linux)上都使用Python v2.7.3。在Windows 7上,我能看到war文件的内容。但是在Linux上,我却看到一个'没有这样的文件或目录'的错误:

$ python example.py
command to be executed is : /usr/local/tools/jdk1.7.0_15/bin/jar tvf jackrabbit-webapp-2.6.5.war
Traceback (most recent call last):
  File "example.py", line 24, in <module>
    read_war()
  File "example.py", line 23, in read_war
    subprocess.call(jar_cmd)
  File "/usr/local/tools/Python-2.7.3/Lib/subprocess.py", line 493, in call
    return Popen(*popenargs, **kwargs).wait()
  File "/usr/local/tools/Python-2.7.3/Lib/subprocess.py", line 679, in __init__
    errread, errwrite)
  File "/usr/local/tools/Python-2.7.3/Lib/subprocess.py", line 1249, in _execute_child
    raise child_exception
OSError: [Errno 2] No such file or directory
$

我在命令提示符下尝试过这个命令 '/usr/local/tools/jdk1.7.0_15/bin/jar tvf jackrabbit-webapp-2.6.5.war',结果是正常的。所以这个命令本身没有问题。我尝试了不同的subprocess.call()组合——传字符串、传列表等等,但都没有成功。任何帮助都非常感谢。

2 个回答

1

使用列表(序列)作为参数,而不是字符串,正如文档中所说

在所有调用中,args是必需的,它应该是一个字符串,或者是一系列程序参数。通常建议提供参数的序列,这样模块可以处理任何需要的转义和引号问题(例如,允许文件名中有空格)。如果传递一个单独的字符串,必须将shell设置为True(见下文),否则这个字符串只能是要执行的程序名称,而不能指定任何参数。

示例:

import os
import subprocess

def read_war():
    war_file_path = "jackrabbit-webapp-2.6.5.war"
    jar_path = os.path.join(os.environ['JAVA_HOME'], 'bin', 'jar')
    jar_cmd = [jar_path, 'tvf', war_file_path]
    print("command to be executed is: %s" % jar_cmd)
    subprocess.check_call(jar_cmd)

read_war()

我使用了check_call,如果命令返回非零的退出状态,就会引发异常。

1

在调用时加上shell=True。对于Windows系统,CreateProcess命令会对字符串进行解析,把命令和它的各种参数分开。而在Linux系统上,只有当你特别告诉子进程要调用shell时,它才会进行字符串处理。否则,它会把你传入的整个字符串当作一个命令,这样就没法正常执行了。

subprocess.call(jar_cmd, shell=True)

撰写回答