使用Python 2.5.1运行时,此代码生成“AttributeError:'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 docs describe this usage。
答案 0 :(得分:10)
三件事
首先,你的()错了。
其次,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))
第三,不要在shell中完成所有tr
和cut
垃圾,很少有东西可能会变慢。在Python中编写tr
和cut
处理 - 它更快更简单。
答案 1 :(得分:3)
脚本中有一些奇怪的东西,
为什么要将每个进程存储在列表中?简单地使用变量会不会更具可读性?删除所有.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()
在每个后续命令中,您已经传递了处理stdout
的Popen对象 not 。从子流程文档的"Replacing shell pipeline"部分,您可以执行..
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)
您不需要使用子进程转义命令/参数,因为子进程不会在任何shell中运行该命令(除非您指定shell=True
)。请参阅子流程文档的Security部分。
而不是..
proc.append(Popen(['svn', 'blame', shellquote(filename)], stdout=PIPE))
..你可以安全地做.. ..
Popen(['svn', 'blame', filename], stdout=PIPE)
正如S.Lott建议的那样,不要使用子进程在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
答案 2 :(得分:1)
您需要该过程的标准输出,因此请将您的stdin=proc[-1]
替换为stdin=proc[-1].stdout
此外,你需要移动你的paren,它应该在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
来电。
答案 3 :(得分:-1)
看起来像语法错误。除了第一次追加其余的都是错误的(审查括号)。
答案 4 :(得分:-2)
像S.Lott所说,用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]