Python/Perlからdiffコマンドを起動して2つの文字列の差分を表示

PythonまたはPerlからfork, execしてdiffコマンドを起動し、2つの文字列の差分を表示させるサンプルコードです。

diffコマンドへの文字列受け渡しは名前付きパイプを使っています。diffしたいだけなのに3つも子プロセスを起動しちゃってます。

Python

import os
import sys
import tempfile

def execDiff(content1, content2, name1 = "1", name2 = "2"):
    sys.stdout.flush()
    # execDiff呼び出す前に標準出力のバッファリングが残っていると
    # fork後に重複して出力される

    # FIFOを置くテンポラリディレクトリ作成
    tmpdir = tempfile.mkdtemp()

    # FIFO作成
    fifo1 = tmpdir + "/" + name1
    fifo2 = tmpdir + "/" + name2
    os.mkfifo(fifo1)
    os.mkfifo(fifo2)

    # diffコマンド起動
    pid = os.fork()
    if pid == 0:
        os.execvp("diff", ["diff", "-u", fifo1, fifo2])

    # 2つの文字列をdiffコマンドに渡すためのプロセスをfork
    pid1 = os.fork()
    if pid1 == 0:
        writer1 = open(fifo1, "w")
        writer1.write(content1)
        writer1.close()
        sys.exit()
    pid2 = os.fork()
    if pid2 == 0:
        writer2 = open(fifo2, "w")
        writer2.write(content2)
        writer2.close()
        sys.exit()

    # 子プロセス終了まで待機
    os.waitpid(pid1, 0)
    os.waitpid(pid2, 0)
    os.waitpid(pid, 0)

    # FIFOとテンポラリディレクトリ削除
    os.remove(fifo1)
    os.remove(fifo2)
    os.rmdir(tmpdir)

execDiff("abc\nghi\n", "abc\ndef\nghi\n", "before", "after")
$ python sample.py
--- /tmp/tmpvvdrq8yq/before     2021-02-28 18:16:39.715880739 +0900
+++ /tmp/tmpvvdrq8yq/after      2021-02-28 18:16:39.715880739 +0900
@@ -1,2 +1,3 @@
 abc
+def
 ghi

Perl

use POSIX qw/mkfifo/;
use File::Temp qw/tempdir/;

sub execDiff {
    my ($content1, $content2, $name1, $name2) = @_;
    $name1 = "1" unless defined($name1);
    $name2 = "2" unless defined($name2);

    # FIFOを置くテンポラリディレクトリ作成
    my $tmpdir = tempdir();

    # FIFO作成
    my $fifo1 = "$tmpdir/$name1";
    my $fifo2 = "$tmpdir/$name2";
    mkfifo($fifo1, 0700) or die $!;
    mkfifo($fifo2, 0700) or die $!;

    # diffコマンド起動
    my $pid = fork;
    die $! unless defined($pid);
    if ($pid == 0) {
        exec("diff", "-u", $fifo1, $fifo2);
    }

    # 2つの文字列をdiffコマンドに渡すためのプロセスをfork
    my $pid1 = fork;
    die $! unless defined($pid1);
    if ($pid1 == 0) {
        open(my $writer1, ">", $fifo1) or die $!;
        print $writer1 $content1;
        close($writer1);
        exit(0);
    }
    my $pid2 = fork;
    die $! unless defined($pid2);
    if ($pid2 == 0) {
        open(my $writer2, ">", $fifo2) or die $!;
        print $writer2 $content2;
        close($writer2);
        exit(0);
    }

    # 子プロセス終了まで待機
    waitpid($pid, 0);
    waitpid($pid1, 0);
    waitpid($pid2, 0);

    # FIFOとテンポラリディレクトリ削除
    unlink($fifo1);
    unlink($fifo2);
    rmdir($tmpdir);
}

execDiff("abc\nghi\n", "abc\ndef\nghi\n", "before", "after");
$ perl sample.pl
--- /tmp/i4YAOgOSeh/before      2021-02-28 18:16:56.985034423 +0900
+++ /tmp/i4YAOgOSeh/after       2021-02-28 18:16:56.985034423 +0900
@@ -1,2 +1,3 @@
 abc
+def
 ghi