Python/Perlから子プロセスの標準入力にデータを渡す
先日も似た記事を書きました。
Python/Perlからdiffコマンドを起動して2つの文字列の差分を表示
このときは、外部プロセスとの通信に名前付きパイプを使いました。
今回は、子プロセスの標準入力に親プロセスからデータを送ります。名前のないパイプを作成し、パイプの読み取り側を子プロセスの標準入力にし、パイプの書き込み側を親プロセスで保持してデータをパイプに書き込みます。
以下のサンプルコードは、子プロセスにwcコマンドを起動して、文字数を数えています。
(プロセスをforkしたり、パイプをごにょごにょしたりする処理はPerlが書きやすいって思っていたのですが、Pythonでも同じようにできるんですね、という発見で、先日の記事も今回の記事も書きました)
Python
import os import sys def exec_wcc(input): sys.stdout.flush() # execDiff呼び出す前に標準出力のバッファリングが残っていると # fork後に重複して出力される reader, writer = os.pipe() # wcコマンド起動 pid = os.fork() if pid == 0: os.close(writer) # 標準入力をパイプからの入力で置き換える os.dup2(reader, 0) # 0は標準入力の意味 os.execvp("wc", ["wc", "-c"]) os.close(reader) # パイプにデータを書き込み writer = os.fdopen(writer, "w") writer.write(input) writer.close() os.waitpid(pid, 0) exec_wcc("Hello, world!") # 13と表示される
Perl
use strict; use warnings; # 上記Pythonの例と同様の # プロセスforkを手動で書く方法 sub exec_wcc_1 { my ($input) = @_; pipe(PIPE_READER, PIPE_WRITER); # wcコマンド起動 my $pid = fork; die $! unless defined($pid); if ($pid == 0) { close(PIPE_WRITER); # 標準入力をパイプからの入力で置き換える open(STDIN, "<&=", fileno(PIPE_READER)) or die $!; exec("wc", "-c"); } close(PIPE_READER); # パイプにデータを書き込み print PIPE_WRITER $input; close(PIPE_WRITER); waitpid($pid, 0); } # Perlっぽい簡潔な書き方 sub exec_wcc_2 { my ($input) = @_; open(WRITER, "|-", "wc -c"); print WRITER $input; close(WRITER); } exec_wcc_1("Hello, world!"); # 13と表示される exec_wcc_2("Hello, world!"); # 13と表示される