pktrain has asked for the wisdom of the Perl Monks concerning the following question:

Hello- Great site, thanks for the help... :)

Anyway, I am in the process of writing a Perl script to create a pipe, read a file list, and pass each file name in the list to the pipe with some selectable delay between sending the file names to the pipe. Another program is called which is set up to read and open the filenames from the pipe and then do some processing on the file it opens. Everything works great if I manually create the pipe by:

$ mknod named.pipe p
$ cat >> named.pipe

and enter the filenames into the pipe by typing the name in the terminal followed by a carriage return, but I can't figure out why this script below isn't doing the job.

It happens that the first file name is put in the pipe, then it is put in immediately again, then the program to read the pipe dies without any error given. Here is the relevant code snippet:

#!/usr/bin/perl -w

# Set parameters here
$obs_file_dir = "/some/path/";
$wait_time = 30;

# Read observed file names to array
$obs_file_list = $obs_file_dir . "file_list.txt";
open(DIR, $obs_file_list) || die("Could not open file!");
@obs_files = <DIR>;
close(DIR);

# Start program to read pipe and process data
system("otherProgramToReadPipe");

# Open pipe
system("mknod named.pipe p");

foreach $file (@obs_files)
{
open(FIFO, ">> named.pipe");
print FIFO $obs_file_dir . $file;
close(FIFO);
sleep $wait_time;
}

close(FIFO);

Thank you for your thoughts!

Replies are listed 'Best First'.
Re: Problem with FIFO
by pc88mxer (Vicar) on Jul 05, 2008 at 14:37 UTC
    When the last writer on a fifo closes its end, the reader will see end of file. Since you are opening and closing the fifo for each line, the reader is only getting one line before seeing EOF.

    Do something like this:

    use FileHandle; ... open(FIFO, ">", "named.pipe") or die "open failed; $!"; FIFO->autoflush(1); ... for $file (@list) { print FIFO $file, "\n"; sleep(...); } close(FIFO);
    Or, have your reader program immediately re-open its end after it detects EOF.
      Yes! I made the changes you suggested and the script now works great. Many thanks... :)
Re: Problem with FIFO
by jethro (Monsignor) on Jul 05, 2008 at 14:32 UTC
    You might change that >> to >. Not sure what that seek to end-of-file on a pipe does, but definitely nothing useful ;-).

    A close(FIFO) sends an EOF to the other side, you shouldn't close the pipe until you are finished with it (or you should expect to see those EOFs on the other side)

    If this still doesn't help, post the code on the other side of the pipe, this is only half the picture

      Thank you for the response. I changed ">>" to ">" and moved the OPEN/CLOSE portion to outside the loop.
Re: Problem with FIFO
by starbolin (Hermit) on Jul 05, 2008 at 15:47 UTC

    To get error messages from your pipe add a SIG handler.

    $SIG{PIPE} = sub { die "Pipe failure" };

    Also you should check the exit value of any pipe closures. See perlipc under "Named Pipes" and "Using open() for IPC.


    s//----->\t/;$~="JAPH";s//\r<$~~/;{s|~$~-|-~$~|||s |-$~~|$~~-|||s,<$~~,<~$~,,s,~$~>,$~~>,, $|=1,select$,,$,,$,,1e-1;print;redo}
      Thank you for the suggestions and the link. That looks to be a great reference for a Perl noobie like myself...
Re: Problem with FIFO
by Anonymous Monk on Jul 05, 2008 at 13:55 UTC
    open FILEHANDLE .... or die "Error opening ... $!";
      Thanks for the reply AM. You're right, I missed that "or" statement. Unfortunately (for me), adding it didn't change the result... :(
Re: Problem with FIFO
by jwkrahn (Abbot) on Jul 05, 2008 at 19:08 UTC

    Another point, instead of:

    system("mknod named.pipe p");

    You should probably use POSIX::mkfifo:

    use POSIX 'mkfifo'; mkfifo 'named.pipe' or die "Cannot create FIFO 'named.pipe' $!";