start page | rating of books | rating of authors | reviews | copyrights

Perl Cookbook

Perl CookbookSearch this book
Previous: 16.4. Reading or Writing to Another Program Chapter 16
Process Management and Communication
Next: 16.6. Preprocessing Input
 

16.5. Filtering Your Own Output

Problem

You want to postprocess your program's output without writing a separate program to do so.

Solution

Use the forking form of open to attach a filter to yourself. For example, this will restrict your program to a hundred lines of output:

head(100); while (<>) {     print; }   sub head {     my $lines = shift || 20;     return if $pid = open(STDOUT, "|-");     die "cannot fork: $!" unless defined $pid;     while (<STDIN>) {         print;         last unless --$lines ;     }      exit; } 

Discussion

It's easy to add an output filter. Just use the forking open on your own STDOUT, and let the child filter STDIN to STDOUT, performing whatever alterations you care about. Notice that we install the output filter before we generate the output. This makes sense - you can't filter your output if it has already left your program. Any such filters should be applied in LIFO order - the last one inserted is the first one run.

Here's an example that uses two output filters. One numbers lines; the other quotes the lines like a mail reply. When run on /etc/motd , you get something like:





1: > Welcome to Linux, version 2.0.33 on a i686



 



2: > 



 



3: >     "The software required `Windows 95 or better', 



 



4: >      so I installed Linux."  



If you reversed the order of the two filters, you'd get:





> 1: Welcome to Linux, Kernel version 2.0.33 on a i686



 



> 2: 



 



> 3:     "The software required `Windows 95 or better', 



 



> 4:      so I installed Linux."  



The program is in Example 16.1 .

Example 16.1: qnumcat

#!/usr/bin/perl # qnumcat - demo additive output filters  number();                   # push number filter on STDOUT quote();                    # push quote filter on STDOUT  while (<>) {                # act like /bin/cat     print; }  close STDOUT;               # tell kids we're done--politely exit;  sub number {     my $pid;     return if $pid = open(STDOUT, "|-");     die "cannot fork: $!" unless defined $pid;     while (<STDIN>) { printf "%d: %s", $., $_ }      exit; }   sub quote {     my $pid;     return if $pid = open(STDOUT, "|-");     die "cannot fork: $!" unless defined $pid;     while (<STDIN>) { print "> $_" }      exit; } 

As with all process forks, doing this a zillion times has some cost, but it's fine for a couple of processes, or even a couple dozen. If the system was actually designed to be multitasking right from the start, as Unix was, this is far cheaper than you imagine. Virtual memory and copy-on-write makes this efficient. Forking is an elegant and inexpensive solution to many, if not most, multitasking needs.

See Also

The open function in Chapter 3 of Programming Perl and in perlfunc (1); Recipe 16.4


Previous: 16.4. Reading or Writing to Another Program Perl Cookbook Next: 16.6. Preprocessing Input
16.4. Reading or Writing to Another Program Book Index 16.6. Preprocessing Input

Library Navigation Links

Copyright © 2001 O'Reilly & Associates. All rights reserved.