subprocess.call()在Mac和Linux上失败
我遇到了一个奇怪的问题,跟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)