【发布时间】:2019-01-16 07:46:32
【问题描述】:
我有许多 shell 命令需要在我的 python 脚本中执行。我知道我不应该像here 中提到的那样使用 shell=true,并且我可以使用 std 输出和输入,以防我在提到的命令中有管道 here。
但问题是我的 shell 命令很复杂并且充满了管道,所以我想创建一个通用方法供我的脚本使用。
我在下面做了一个小测试,但打印结果后挂了(我简化了只是放在这里)。谁能告诉我:
- 为什么会挂起。
- 如果有更好的方法来做到这一点。
谢谢。
PS:这只是一个大型 python 项目的一小部分,我尝试这样做是有商业原因的。谢谢。
#!/usr/bin/env python3
import subprocess as sub
from subprocess import Popen, PIPE
import shlex
def exec_cmd(cmd,p=None,isFirstLoop=True):
if not isFirstLoop and not p:
print("Error, p is null")
exit()
if "|" in cmd:
cmds = cmd.split("|")
while "|" in cmd:
# separates what is before and what is after the first pipe
now_cmd = cmd.split('|',1)[0].strip()
next_cmd = cmd.split('|',1)[-1].strip()
try:
if isFirstLoop:
p1 = sub.Popen(shlex.split(now_cmd), stdout=PIPE)
exec_cmd(next_cmd,p1,False)
else:
p2 = sub.Popen(shlex.split(now_cmd),stdin=p.stdout, stdout=PIPE)
exec_cmd(next_cmd,p2,False)
except Exception as e:
print("Error executing command '{0}'.\nOutput:\n:{1}".format(cmd,str(e)))
exit()
# Adjust cmd to execute the next part
cmd = next_cmd
else:
proc = sub.Popen(shlex.split(cmd),stdin=p.stdout, stdout=PIPE, universal_newlines=True)
(out,err) = proc.communicate()
if err:
print(str(err).strip())
else:
print(out)
exec_cmd("ls -ltrh | awk '{print $9}' | wc -l ")
【问题讨论】:
-
您可能会在代码审查堆栈交换网站上发布此内容。正如我所看到的,解析命令的方式存在一些潜在问题,与
shell=True的问题非常相似……这段代码也好不了多少。其次,如果您使用stdout=PIPE创建管道,则可以传递stdin=proc.stdout以使用相同的管道,这是连接程序的更好方法。但这需要一点思考。 -
很好,让我试试这两个建议。谢谢。
-
@DietrichEpp 代码审查既不接受不工作的代码,也不接受为演示特定行为而简化的代码。这个问题有一个明确的问题(代码挂起),可以在 SO 上解决。
-
@DietrichEpp,我相信您的答案也应该添加到下面的答案中。谢谢。
标签: python shell subprocess