此代码生成“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))

三,不要做外壳所有trcut垃圾,一些事情可能会更慢。用Python语言编写的trcut处理 - 这是更快,更简单

其他提示

剧本里有一些奇怪的地方

  • 为什么要将每个进程存储在列表中?简单地使用变量不是更具可读性吗?删除所有 .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]
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top