0

通常、STDIN/STDOUT を介したデータの受け渡しは簡単なので、これは大きな問題ではありません。

しかし、私は差分ユーティリティに取り組んでおり、これには 2 つの入力と 1 つの出力があります。

検討:

diff <(curl 'http://google.com') <(curl 'https://google.com')
5c5
< <A HREF="http://www.google.com/">here</A>.
---
> <A HREF="https://www.google.com/">here</A>.

open(sys.argv[1], 'r').read()argv[1] と argv[2] の両方のデータを正常に取得できるため、これは単純な古い python プログラムで問題ありません。

問題は、私の差が google_diff_match_patch の C++ 実装であり、物事を単純にするために、そのプログラムを呼び出していることです (これは、 、、およびargvを使用して s を読み取ります)。wifstreamwstringgetline

したがって、今起こらなければならないことは、 my/dev/fd/11を myに「与える」必要があるということですが、パス (通常はそうです)をC++ プログラムへの引数としてsubprocess.Popen(['dmp'])詰め込むことができないようです。 python プログラムの./dev/fd/11/dev/fd/12dmp/dev/fd/11/dev/fd/11

問題をさらに混乱させるにはfile、「バイナリファイル」オラクルとして使用しているため、ファイルを子に送信する前にファイルの内容を読み取る必要があります。

file_process = Popen(['file', '-'], stdin=PIPE, stdout=PIPE)
file_content = open(filename, 'r').read()
(filetype, err) = file_process.communicate(file_content)
if filetype.find('text') == -1:
    # Popen my c++ program and try to feed it file_content

「ファイルに書き込む」などの回答はしないでください。これらの入力リダイレクト fifo を実装して、プログラムを他のコマンド ライン diff と同じくらい効果的に使用できるようにしたいと考えていcurlます (たとえば、ファイルに保存せずにネットから何かを ing することも含まれます)。

編集:引数がデフォルト値のFalseの場合、子によるとsubprocess、ファイル記述子を継承する必要があります。close_fdsさて、これは、私のpythonラッパープログラムで呼び出しopen('/dev/fd/11')て閉じず、 を使用して子をフォークした場合Popen()、その子は何らかの形でファイル記述子11を読み取ることができるはずであることを示しているようです。

では、Python のファイル記述子 11 の内容を取得したので、子供が読み取るファイルをどのように設定すればよいでしょうか? たとえば、シェルの機能を複製する方法( and<(echo file contents)を使用せずに、今すぐ実行する必要があることを認識しています)shell=Trueecho

4

1 に答える 1

1

引数としてファイル名を期待している外部実行可能ファイルがあり、代わりに Python スクリプトから開いているファイル記述子を渡したいと思われますよね?そして、これらのファイル記述子は実際のファイルではない可能性がありますstdin。または他のパイプである可能性がありますか?

その場合、簡単な作業はできません。アプリケーションは、開いているファイルではなく、ファイル名を想定しています。その実行可能ファイルのコードはファイルを名前で開いているため、Python スクリプトからその動作を変更することはできません。たとえ実行可能ファイルがファイル記述子を継承していたとしても、そのコードはその仮定を念頭に置いて書かれている必要があります。その実行可能ファイルのコードがあなたが提案していることを実行できないということではありません。それを実行するように書かれていないだけです。したがって、あなたがしようとしているのは回避策であり、必ずしもクリーンなオプションがあるとは限りません。

あなたは、ファイルへの書き込みを伴うソリューションは望まないとおっしゃっていますが、最小限の作業を行っている場合は、それが最も簡単なオプションであることを指摘しておく必要があると思います。ディスクへの書き込みが心配な場合は、tmpfsパーティションなどを作成できますが、それはかなり面倒です (そしてあまり移植性がありません)。

次の最も簡単な方法は、サードパーティの実行可能ファイルを使用するのではなく、Google ライブラリを直接呼び出す C 拡張機能を作成することです。これは/proc/self/fd、何かをいじるよりもかなりクリーン (かつ移植性が高い) と言えます。実際、プロジェクトを確認したところ、既に Python API が提供されているので、それを直接呼び出さない理由はありますか? 個人的には、これは間違いなく私が取っているアプローチです。

編集: ああ、Python API が C++ モジュールのラッパーではなく純粋な Python であることを発見したので、パフォーマンス上の理由からそれを使用していない可能性があります。厳しいパフォーマンス要件がない限り、これが最も簡単なオプションだと思いますが、C++ のパフォーマンスが本当に必要な場合は、独自のラッパーを作成するオプションがあります。

実行可能ファイルを呼び出すことに本当に意図があり、中間ファイルに書き込みたくない場合は、ファイルを使用できると思いますが/dev/fd/*、これは実際のファイルに対してのみ機能する可能性があります。少なくとも Linux では、これらのファイルはファイルシステム上の基になるファイルへのシンボリック リンクであるため、実行可能ファイルがシンボリック リンクを介してそれらを再度開くと、各ファイルの先頭で読み取りポインターが取得され、正しく diff を実行できるようになります。

ただし、の場合、stdin実際のファイルではなくパイプを扱っているため、このトリックが機能するとは思えません。試してみると、同じ基礎となるパイプが読み取り用に開かれている 2 つのプロセスが作成されます。これは、パイプからの出力がランダムな子プロセスに到達することを意味します (完全にランダムではありませんが、あなたの観点からは予測できません)。現在、プロセスが読み取りを行っていない限り、stdinこれを回避できる可能性がありますが、これを行うのはかなり疑わしいことです。

要するに、/proc/self/fdファイルを開くだけで済むかもしれませんが (または/dev/fd、必要に応じて)、それはお勧めできません。使用している実行可能ファイルが目的の方法でライブラリを呼び出さない場合は、独自の Python C 拡張ラッパーを作成するか、既に利用可能な Python API を使用して、ライブラリを直接呼び出すことをお勧めします。

于 2013-07-01T12:04:31.577 に答える