调试subprocess.Popen调用
我之前一直在用 subprocess.Popen
很顺利,主要是用它来把一些程序包装在 Python 脚本里,以便格式化参数或进行一些自定义操作。
这次我在开发一个新的包装器时,照常操作,但却没有任何反应。
这是我写的简单代码:
print command
p = subprocess.Popen(command, shell = True)
result = p.communicate()[0]
print vars(p)
return result
这是输出结果:
/usr/bin/sh /tmp/run/launch.sh
{'_child_created': True, 'returncode': 0, 'stdout': None, 'stdin': None, 'pid': 21650, 'stderr': None, 'universal_newlines': False}
正如你所看到的,我的目标是创建一个 shell 脚本,设置好我需要的一切,然后执行它。我更希望使用真正的 Python 代码,但不幸的是,launch.sh
调用了第三方的 shell 脚本,我不想去尝试复制这些脚本(尽管我已经坚持要求提供 Python 接口超过一年了)。
问题是:
- 这个 shell 脚本没有被执行(它应该会启动一个进程并输出一些小信息)
- 没有抛出任何 Python 异常
- 在
p
对象中没有任何指示错误发生的迹象
我也试过 check_call
,但也没有成功...
我现在不知道该怎么办,如果有人能指出我的错误或给我一些解决方案,我会非常感激...
编辑:
- 我在 Linux(sh)上尝试运行这个
- 脚本中需要 shell 来进行变量替换
编辑 2:
根据 badp
的建议,我调整了代码并添加了:
subprocess.Popen('ps', shell = True).communicate()
在创建进程的 p = ...
这一行后,输出结果是:
/usr/bin/sh /tmp/run/launch.sh
PID TTY TIME CMD
29978 pts/0 00:00:01 zsh
1178 pts/0 00:00:01 python
1180 pts/0 00:00:00 sh <defunct>
1181 pts/0 00:00:00 ps
None
显然进程已经启动(尽管显示为 <defunct>
),另外我还注意到我在传递参数时遇到了一些小问题...
谢谢。
2 个回答
试试这个:
p = subprocess.Popen(command,
shell = True, #is this even needed?
stdin = subprocess.PIPE,
stdout = subprocess.PIPE,
# stderr = subprocess.STDOUT #uncomment if reqd
)
在Windows上用ping
命令测试过,效果很好。这个命令可以让你进行通信
,可能会帮助你找出为什么脚本一开始没有被启动的原因哦 :)
我终于找到了我的问题的答案,感谢 badp
和他提供的调试建议。
在 Python 的 subprocess 模块 页面上提到:
executable 参数指定要执行的程序。这个参数很少需要使用:通常要执行的程序是通过 args 参数来定义的。如果
shell=True
,那么 executable 参数就指定了要使用哪个 shell。在 Unix 系统中,默认的 shell 是/bin/sh
。在 Windows 系统中,默认的 shell 是由COMSPEC
环境变量指定的。你在 Windows 上需要指定shell=True
的唯一原因是你想执行的命令实际上是内置在 shell 中的,比如dir
或copy
。运行批处理文件或控制台可执行文件时并不需要shell=True
。
因为我在 Linux 上并且使用了 shell=True
,所以我的命令实际上是一个要由 executable 执行的参数列表,默认值是 /bin/sh
。因此,实际执行的完整命令是:/bin/sh /usr/bin/sh /tmp/run/launch.sh
... 结果并不是很好。
我应该使用以下任意一种:
subprocess.Popen('/tmp/run/launch.sh', shell=True)
或者
subprocess.Popen('/tmp/run/launch.sh', executable = '/usr/bin/sh', shell=True)
有点棘手的是,shell=True
只会在 Linux 上修改默认的 executable 值...