screen の backtick をいつか使う(mkfifo使用)

screen の backtick をいつか使う - l1o0の日記 でファイルの変更を読み取るのに、周期的にファイルを監視していたが、kazuhoのメモ置き場 を参考に、mkfifoを使えば簡単にプロセス間通信を実現できることがわかった。

mkfifo

mkfifoを使えばファイルをI/Fとして簡単にプロセス間通信を実現できる。例えば、以下のスクリプトを実行すると、

mkfifo.sh

#!/bin/sh

fifo_file="/tmp/tmp$$.fifo"
rm -f $fifo_file
trap "rm -f $fifo_file; exit 1" 1 2 3 15
mkfifo -m 666 $fifo_file

grep -i "init" $fifo_file | grep -v "grep" > result.txt &
ps aux > $fifo_file

rm -f $fifo_file
$ sh mkfifo.sh
$ cat result.txt 
root         1  0.0  0.0   2112   740 ?        Ss   02:38   0:01 init [5]  

となる。バックグランド(つまり別プロセス)で動いているgrepと、fifoファイルを通して通信できていることがわかる。

ファイルのリダイレクト以外でも、オプションでファイル出力するタイプのコマンドでも同じことができる。

mkfifo_f.sh

#!/bin/sh

fifo_file="/tmp/tmp$$.fifo"
rm -f $fifo_file
trap "rm -f $fifo_file; exit 1" 1 2 3 15
mkfifo -m 666 $fifo_file

grep -i "open" $fifo_file > result.txt &
strace -o $fifo_file ls

rm -f $fifo_file
$ sh mkfifo_f.sh
$ cat result.txt 
open("/etc/ld.so.cache", O_RDONLY)      = 3
open("/lib/libselinux.so.1", O_RDONLY)  = 3
open("/lib/i686/cmov/librt.so.1", O_RDONLY) = 3
open("/lib/libacl.so.1", O_RDONLY)      = 3
open("/lib/i686/cmov/libc.so.6", O_RDONLY) = 3
open("/lib/i686/cmov/libdl.so.2", O_RDONLY) = 3
open("/lib/i686/cmov/libpthread.so.0", O_RDONLY) = 3
open("/lib/libattr.so.1", O_RDONLY)     = 3
open("/proc/filesystems", O_RDONLY|O_LARGEFILE) = 3
open("/usr/lib/locale/locale-archive", O_RDONLY|O_LARGEFILE) = 3
open(".", O_RDONLY|O_NONBLOCK|O_LARGEFILE|O_DIRECTORY|O_CLOEXEC) = 3

strace の -o オプションでファイルの出力先としてfifo ファイルを指定して、別プロセスで動いている grep にコマンド出力を渡している。

backtickスクリプトの変更

ということで、screen の backtick をいつか使う - l1o0の日記で使っていたperlスクリプトを以下のようにした。

#!/usr/bin/perl
use strict;
use warnings;
use IO::File;
use Path::Class qw(file);
use POSIX qw(mkfifo);

my $fifo = file( $ENV{HOME}, 'tmp', 'backtick.fifo' );
unlink $fifo;
if ( !mkfifo( $fifo, 0666 ) ) {
    die "$!";
}

while (1) {
    open my $fh, '<', $fifo or die "$fifo, $!";
    while ( my $line = <$fh> ) {
        $line =~ s/\x0D?\x0A?$//;
        print $line, $/;
        (*STDOUT)->flush;
    }
    close $fh or die "$fifo, $!";
}