Python子进程“对象没有属性'fileno'”错误

时间:2021-08-07 07:57:01

This code generates "AttributeError: 'Popen' object has no attribute 'fileno'" when run with Python 2.5.1

当使用Python 2.5.1运行时,此代码生成“AttributeError:'Popen'对象没有属性'fileno'”

Code:

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()

Stack:

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()

This code should be working the python docs describe this usage.

这段代码应该是python docs描述这种用法。

5 个解决方案

#1


Three things

First, your ()'s are wrong.

首先,你的()错了。

Second, the result of subprocess.Popen() is a process object, not a file.

其次,subprocess.Popen()的结果是一个进程对象,而不是一个文件。

proc = []
proc.append(Popen(['svn', 'blame', shellquote(filename)], stdout=PIPE))
proc.append(Popen(['tr', '-s', r"'\040'"], stdin=proc[-1]), stdout=PIPE)

The value of proc[-1] isn't the file, it's the process that contains the file.

proc [-1]的值不是文件,而是包含文件的进程。

proc.append(Popen(['tr', '-s', r"'\040'"], stdin=proc[-1].stdout, stdout=PIPE))

Third, don't do all that tr and cut junk in the shell, few things could be slower. Write the tr and cut processing in Python -- it's faster and simpler.

第三,不要在shell中完成所有tr和切割垃圾,很少有东西可能会变慢。在Python中编写tr和cut处理 - 它更快更简单。

#2


There's a few weird things in the script,

脚本中有一些奇怪的东西,

  • Why are you storing each process in a list? Wouldn't it be much more readable to simply use variables? Removing all the .append()s reveals an syntax error, several times you have passed stdout=PIPE to the append arguments, instead of Popen:

    为什么要将每个进程存储在列表中?简单地使用变量会不会更具可读性?删除所有.append()会显示语法错误,有几次你已经将stdout = PIPE传递给append参数,而不是Popen:

    proc.append(Popen(...), stdout=PIPE)
    

    So a straight-rewrite (still with errors I'll mention in a second) would become..

    因此,直接重写(仍然会在一秒钟内提到错误)将成为......

    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()
    
  • On each subsequent command, you have passed the Popen object, not that processes stdout. From the "Replacing shell pipeline" section of the subprocess docs, you do..

    在每个后续命令中,您已经传递了Popen对象,而不是处理stdout。从子流程文档的“替换shell管道”部分,您可以...

    p1 = Popen(["dmesg"], stdout=PIPE)
    p2 = Popen(["grep", "hda"], stdin=p1.stdout, stdout=PIPE)
    

    ..whereas you were doing the equivalent of stdin=p1.

    ..你做的相当于stdin = p1。

    The tr1 = (in the above rewritten code) line would become..

    tr1 =(在上面的重写代码中)行将成为..

    tr1 = Popen(['tr', '-s', r"'\040'"], stdin=blame.stdout, stdout=PIPE)
    
  • You do not need to escape commands/arguments with subprocess, as subprocess does not run the command in any shell (unless you specify shell=True). See the Securitysection of the subprocess docs.

    您不需要使用子进程转义命令/参数,因为子进程不在任何shell中运行该命令(除非您指定shell = True)。请参阅子流程文档的安全性部分。

    Instead of..

    proc.append(Popen(['svn', 'blame', shellquote(filename)], stdout=PIPE))
    

    ..you can safely do..

    ..你可以安全地做..

    Popen(['svn', 'blame', filename], stdout=PIPE)
    
  • As S.Lott suggested, don't use subprocess to do text-manipulations easier done in Python (the tr/cut commands). For one, tr/cut etc aren't hugely portable (different versions have different arguments), also they are quite hard to read (I've no idea what the tr's and cut are doing)

    正如S.Lott建议的那样,不要使用子进程在Python中更容易地完成文本操作(tr / cut命令)。对于一个,tr / cut等不是非常便携(不同的版本有不同的参数),它们也很难读(我不知道tr和cut正在做什么)

    If I were to rewrite the command, I would probably do something like..

    如果我要重写命令,我可能会做类似的事情......

    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
    

#3


You want the stdout of the process, so replace your stdin=proc[-1] with stdin=proc[-1].stdout

你想要进程的stdout,所以用stdin = proc [-1]替换你的stdin = proc [-1] .stdout

Also, you need to move your paren, it should come after the stdout argument.

此外,你需要移动你的paren,它应该在stdout参数之后。

 proc.append(Popen(['tr', '-s', r"'\040'"], stdin=proc[-1]), stdout=PIPE)

should be:

 proc.append(Popen(['tr', '-s', r"'\040'"], stdin=proc[-1].stdout, stdout=PIPE))

Fix your other append calls in the same way.

以相同的方式修复您的其他追加调用。

#4


looks like syntax error. except first append the rest are erroneous (review brackets).

看起来像语法错误。除了第一次追加其余的都是错误的(审查括号)。

#5


Like S.Lott said, processing the text in Python is better.

就像S.Lott所说,用Python处理文本更好。

But if you want to use the cmdline utilities, you can keep it readable by using shell=True:

但是如果要使用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]

#1


Three things

First, your ()'s are wrong.

首先,你的()错了。

Second, the result of subprocess.Popen() is a process object, not a file.

其次,subprocess.Popen()的结果是一个进程对象,而不是一个文件。

proc = []
proc.append(Popen(['svn', 'blame', shellquote(filename)], stdout=PIPE))
proc.append(Popen(['tr', '-s', r"'\040'"], stdin=proc[-1]), stdout=PIPE)

The value of proc[-1] isn't the file, it's the process that contains the file.

proc [-1]的值不是文件,而是包含文件的进程。

proc.append(Popen(['tr', '-s', r"'\040'"], stdin=proc[-1].stdout, stdout=PIPE))

Third, don't do all that tr and cut junk in the shell, few things could be slower. Write the tr and cut processing in Python -- it's faster and simpler.

第三,不要在shell中完成所有tr和切割垃圾,很少有东西可能会变慢。在Python中编写tr和cut处理 - 它更快更简单。

#2


There's a few weird things in the script,

脚本中有一些奇怪的东西,

  • Why are you storing each process in a list? Wouldn't it be much more readable to simply use variables? Removing all the .append()s reveals an syntax error, several times you have passed stdout=PIPE to the append arguments, instead of Popen:

    为什么要将每个进程存储在列表中?简单地使用变量会不会更具可读性?删除所有.append()会显示语法错误,有几次你已经将stdout = PIPE传递给append参数,而不是Popen:

    proc.append(Popen(...), stdout=PIPE)
    

    So a straight-rewrite (still with errors I'll mention in a second) would become..

    因此,直接重写(仍然会在一秒钟内提到错误)将成为......

    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()
    
  • On each subsequent command, you have passed the Popen object, not that processes stdout. From the "Replacing shell pipeline" section of the subprocess docs, you do..

    在每个后续命令中,您已经传递了Popen对象,而不是处理stdout。从子流程文档的“替换shell管道”部分,您可以...

    p1 = Popen(["dmesg"], stdout=PIPE)
    p2 = Popen(["grep", "hda"], stdin=p1.stdout, stdout=PIPE)
    

    ..whereas you were doing the equivalent of stdin=p1.

    ..你做的相当于stdin = p1。

    The tr1 = (in the above rewritten code) line would become..

    tr1 =(在上面的重写代码中)行将成为..

    tr1 = Popen(['tr', '-s', r"'\040'"], stdin=blame.stdout, stdout=PIPE)
    
  • You do not need to escape commands/arguments with subprocess, as subprocess does not run the command in any shell (unless you specify shell=True). See the Securitysection of the subprocess docs.

    您不需要使用子进程转义命令/参数,因为子进程不在任何shell中运行该命令(除非您指定shell = True)。请参阅子流程文档的安全性部分。

    Instead of..

    proc.append(Popen(['svn', 'blame', shellquote(filename)], stdout=PIPE))
    

    ..you can safely do..

    ..你可以安全地做..

    Popen(['svn', 'blame', filename], stdout=PIPE)
    
  • As S.Lott suggested, don't use subprocess to do text-manipulations easier done in Python (the tr/cut commands). For one, tr/cut etc aren't hugely portable (different versions have different arguments), also they are quite hard to read (I've no idea what the tr's and cut are doing)

    正如S.Lott建议的那样,不要使用子进程在Python中更容易地完成文本操作(tr / cut命令)。对于一个,tr / cut等不是非常便携(不同的版本有不同的参数),它们也很难读(我不知道tr和cut正在做什么)

    If I were to rewrite the command, I would probably do something like..

    如果我要重写命令,我可能会做类似的事情......

    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
    

#3


You want the stdout of the process, so replace your stdin=proc[-1] with stdin=proc[-1].stdout

你想要进程的stdout,所以用stdin = proc [-1]替换你的stdin = proc [-1] .stdout

Also, you need to move your paren, it should come after the stdout argument.

此外,你需要移动你的paren,它应该在stdout参数之后。

 proc.append(Popen(['tr', '-s', r"'\040'"], stdin=proc[-1]), stdout=PIPE)

should be:

 proc.append(Popen(['tr', '-s', r"'\040'"], stdin=proc[-1].stdout, stdout=PIPE))

Fix your other append calls in the same way.

以相同的方式修复您的其他追加调用。

#4


looks like syntax error. except first append the rest are erroneous (review brackets).

看起来像语法错误。除了第一次追加其余的都是错误的(审查括号)。

#5


Like S.Lott said, processing the text in Python is better.

就像S.Lott所说,用Python处理文本更好。

But if you want to use the cmdline utilities, you can keep it readable by using shell=True:

但是如果要使用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]