Python子进程“对象没有属性'fileno'”错误
-
13-09-2019 - |
题
此代码生成“AttributeError:使用 Python 2.5.1 运行时,“Popen”对象没有属性“fileno””
代码:
def get_blame(filename):
proc = []
proc.append(Popen(['svn', 'blame', shellquote(filename)], stdout=PIPE))
proc.append(Popen(['tr', '-s', r"'\040'"], stdin=proc[-1]), stdout=PIPE)
proc.append(Popen(['tr', r"'\040'", r"';'"], stdin=proc[-1]), stdout=PIPE)
proc.append(Popen(['cut', r"-d", r"\;", '-f', '3'], stdin=proc[-1]), stdout=PIPE)
return proc[-1].stdout.read()
堆:
function walk_folder in blame.py at line 55
print_file(os.path.join(os.getcwd(), filename), path)
function print_file in blame.py at line 34
users = get_blame(filename)
function get_blame in blame.py at line 20
proc.append(Popen(['tr', '-s', r"'\040'"], stdin=proc[-1]), stdout=PIPE)
function __init__ in subprocess.py at line 533
(p2cread, p2cwrite,
function _get_handles in subprocess.py at line 830
p2cread = stdin.fileno()
这段代码应该可以按照 python 文档描述的那样工作 这个用法.
解决方案
三样东西
首先,你的()的是错误的。
其次,subprocess.Popen()
的结果是一个过程对象,而不是一个文件。
proc = []
proc.append(Popen(['svn', 'blame', shellquote(filename)], stdout=PIPE))
proc.append(Popen(['tr', '-s', r"'\040'"], stdin=proc[-1]), stdout=PIPE)
proc[-1]
的值是不是文件,它包含文件的过程。
proc.append(Popen(['tr', '-s', r"'\040'"], stdin=proc[-1].stdout, stdout=PIPE))
三,不要做外壳所有tr
和cut
垃圾,一些事情可能会更慢。用Python语言编写的tr
和cut
处理 - 这是更快,更简单
其他提示
剧本里有一些奇怪的地方
为什么要将每个进程存储在列表中?简单地使用变量不是更具可读性吗?删除所有
.append()s
显示语法错误,多次将 stdout=PIPE 传递给append
参数,而不是 Popen:proc.append(Popen(...), stdout=PIPE)
因此,直接重写(仍然有错误,我稍后会提到)将变成..
def get_blame(filename): blame = Popen(['svn', 'blame', shellquote(filename)], stdout=PIPE) tr1 = Popen(['tr', '-s', r"'\040'"], stdin=blame, stdout=PIPE) tr2 = Popen(['tr', r"'\040'", r"';'"], stdin=tr1), stdout=PIPE) cut = Popen(['cut', r"-d", r"\;", '-f', '3'], stdin=tr2, stdout=PIPE) return cut.stdout.read()
在每个后续命令中,您都传递了 Popen 对象, 不是 那个过程
stdout
. 。来自 《更换外壳管道》 子流程文档的部分,你做..p1 = Popen(["dmesg"], stdout=PIPE) p2 = Popen(["grep", "hda"], stdin=p1.stdout, stdout=PIPE)
..而你所做的相当于
stdin=p1
.这
tr1 =
(在上面重写的代码中)行将变成..tr1 = Popen(['tr', '-s', r"'\040'"], stdin=blame.stdout, stdout=PIPE)
您不需要使用 subprocess 转义命令/参数,因为 subprocess 不会在任何 shell 中运行该命令(除非您指定
shell=True
)。请参阅 安全子流程文档的部分。代替..
proc.append(Popen(['svn', 'blame', shellquote(filename)], stdout=PIPE))
..你可以安全地做..
Popen(['svn', 'blame', filename], stdout=PIPE)
正如 S.Lott 建议的那样,不要使用 subprocess 来进行在 Python 中更容易完成的文本操作(tr/cut 命令)。一方面,tr/cut 等并不是非常可移植(不同版本有不同的参数),而且它们也很难阅读(我不知道 tr 和 cut 正在做什么)
如果我要重写命令,我可能会做类似的事情。
def get_blame(filename): blame = Popen(['svn', 'blame', filename], stdout=PIPE) output = blame.communicate()[0] # preferred to blame.stdout.read() # process commands output: ret = [] for line in output.split("\n"): split_line = line.strip().split(" ") if len(split_line) > 2: rev = split_line[0] author = split_line[1] line = " ".join(split_line[2:]) ret.append({'rev':rev, 'author':author, 'line':line}) return ret
您想要的过程的标准输出,所以用stdin=proc[-1]
取代你stdin=proc[-1].stdout
此外,你需要将你的括号,它应该在stdout
争吵后。
proc.append(Popen(['tr', '-s', r"'\040'"], stdin=proc[-1]), stdout=PIPE)
应该是:
proc.append(Popen(['tr', '-s', r"'\040'"], stdin=proc[-1].stdout, stdout=PIPE))
修正以同样的方式你的其他append
电话。
看起来像语法错误。除了第一附加其余的都是错误(审查括号中)。
像美国洛特所述,处理在Python文本更好。
但是,如果你想使用的cmdline工具,您可以通过使用shell=True
保持可读:
cmdline = r"svn blame %s | tr -s '\040' | tr '\040' ';' | cut -d \; -f 3" % shellquote(filename)
return Popen(cmdline, shell=True, stdout=PIPE).communicate()[0]