代码之家  ›  专栏  ›  技术社区  ›  epochwolf

python subprocess“对象没有属性”fileno“错误

  •  7
  • epochwolf  · 技术社区  · 15 年前

    当使用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文档描述的 this usage .

    5 回复  |  直到 8 年前
        1
  •  10
  •   S.Lott    15 年前

    三件事

    首先,你的()是错误的。

    第二,结果 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 垃圾在壳里,很少有东西能慢一点。写下 TR 用python处理——它更快更简单。

        2
  •  3
  •   dbr    15 年前

    剧本里有一些奇怪的东西,

    • 为什么要将每个进程存储在一个列表中?仅仅使用变量是否更容易阅读?移除所有 .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 . 从 "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
      
        3
  •  1
  •   Jason Coon    15 年前

    您希望stdout退出进程,因此请替换 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 以同样的方式呼叫。

        4
  •  -1
  •   SilentGhost    15 年前

    似乎是语法错误。除了第一个附加,其余的都是错误的(复习括号)。

        5
  •  -2
  •   orip    15 年前

    正如S.Lott所说,用Python处理文本更好。

    但是,如果要使用命令行实用程序,可以使用 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]