2009-04-22 11 views
7

"オブジェクトが 'FILENOを' は属性を持っていない" このコードは、 "はAttributeError: 'popenの' オブジェクトが 'FILENOを' は属性を持っていない" を生成2.5.1Pythonのサブプロセスのエラー

コードはPythonで実行すると:

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を記述する作業をする必要があります。

+4

はばかげています。これはプログラミングの問題の性質です。狭いユーザベースには常にニッチな問題があります。しかし、彼らは有用です...私は今、私はそれをそれ以上頻繁に使用しない理由ですが、私は悲しいです。 – Dan

答えて

10

3つのもの

まず、あなたの()は間違っています。

第2に、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ジャンクをしない、いくつかのことが遅くなる可能性があります。 trcutの処理をPythonで記述すると、処理が高速かつ簡単になります。スクリプト内のいくつかの奇妙な事があります

+0

ユーモアのための 'ツリー'でしたか? –

+0

コメントありがとうございます。修正されました。 –

+0

スクリプトはlinux上でのみ使用されます。それは他の何よりもツールから離れたものです。シェルツールを使うことは、Pythonに相当するものを見つけようとするよりも簡単でした。動作中のシェルコマンドをドロップするだけで、正規表現をデバッグするよりも簡単です。 – epochwolf

-1

は構文エラーのようです。残りの部分には誤りがあります(レビュー括弧)。

+0

実際にはありません。 – epochwolf

+0

それは何ではないのですか?すべての答えには、あなたの括弧で問題があるという事実が含まれていました!それはもちろん、パイプの上に構文の問題です。 – SilentGhost

+0

これは構文上の問題ですが、文法上のエラーではありません。コードは、私が持っていたスクリプトから直接貼り付けられます。エラーは生成されたエラーです。構文エラーにより、関数定義の途中でスクリプトが強制終了されてしまいます。この関数は実際に呼び出されます。私はlist.append()が複数の引数を受け付けるからだと思います。 – epochwolf

1

あなたは、プロセスの標準出力をしたいので、あなたの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呼び出しを修正します。

3

  • は、なぜあなたは、リスト内の各プロセスを格納していますか?単純に変数を使用すると読みやすくなりませんか? (まだエラーで私は2番目に言及します)

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

    ので、ストレート・リライト:すべての.append()sを削除すると、あなたが代わりにpopenのを、append引数に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 = Popen(['tr', '-s', r"'\040'"], stdin=blame.stdout, stdout=PIPE) 
    
  • ラインになるでしょう(上記の書き換えコードで)tr1 = ...(しない限り、 shell=Trueと指定します)。サブプロセスドキュメントのSecurityセクションを参照してください。

    の代わりに...

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

    S.Lottが示唆したように..youは安全に簡単に行われ、テキストの操作を行うには、サブプロセスを使用していない..

    Popen(['svn', 'blame', filename], stdout=PIPE) 
    
  • を行うことができますPython(tr/cutコマンド)。 1つは、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

よう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] 
+1

shell = Trueを使用すると、実際のエラー処理を行わずに、あるコマンドから次のコマンドへデータをパイプする間にプロセスがハングする可能性があります。 – SummerEla

+0

@SummerEla十分に公正ですが、それはトレードオフです - 人々はいつもシェルスクリプトでそれを受け入れます。 Pythonでスクリプトを書くときにも同じトレードオフを行うことが可能です。読みやすさとシンプルさにも価値があります – orip