[comp.lang.perl] Problem piping binary data

al@ee.pitt.edu (Alan Martello) (07/17/90)

I give up.  I want to pipe binary data from one program to another
while (possibly) filtering it.

Why doesn't this work and how can it be modified to work?

------------------------------------------------------------------------
---------
#!/bin/perl -P

#
#  this works (of course) since the shell does the pipe
#
system("cat /vmunix | dd of=./vmunix_copy1");

#
#  how can I make perl do the same thing explicitly ?
#  THIS DOESN'T WORK
#
open(TMPFH,"cat /vmunix | ");
open(OUTFH, "| dd of=./vmunix_copy2");

while(<TMPFH>)
{
    printf OUTFH $line;
    read(TMPFH, $line, $length);
}

close(OUTFH);
close(TMPFH);

------------------------------------------------------------------------
---------

*******************************************************************
       Alan R. Martello        Electrical Engineering Dept.
        al@ee.pitt.edu           University of Pittsburgh
*******************************************************************

merlyn@iwarp.intel.com (Randal Schwartz) (07/18/90)

In article <8120@pitt.UUCP>, al@ee (Alan Martello) writes:
| I give up.  I want to pipe binary data from one program to another
| while (possibly) filtering it.
| 
| Why doesn't this work and how can it be modified to work?
| 
| ------------------------------------------------------------------------
| open(TMPFH,"cat /vmunix | ");
| open(OUTFH, "| dd of=./vmunix_copy2");
| 
| while(<TMPFH>)
| {
|     printf OUTFH $line;
|     read(TMPFH, $line, $length);
| }
| 
| close(OUTFH);
| close(TMPFH);

The "printf" is your culprit.  It's probably eating every single
%-escape and null character in the string.

Replace that with

	print OUTFH $line

and you'll be able to sleep at night.  I know I do. :-)

printf "%c%c%c%c%s",ord("J"),ord("u"),ord("s"),ord("t")," another Perl hacker,"
-- 
/=Randal L. Schwartz, Stonehenge Consulting Services (503)777-0095 ==========\
| on contract to Intel's iWarp project, Beaverton, Oregon, USA, Sol III      |
| merlyn@iwarp.intel.com ...!any-MX-mailer-like-uunet!iwarp.intel.com!merlyn |
\=Cute Quote: "Welcome to Portland, Oregon, home of the California Raisins!"=/

kai@sp1.csrd.uiuc.edu (Kuck And Associates) (07/18/90)

al@ee.pitt.edu (Alan Martello) writes:

>Why doesn't this work and how can it be modified to work?

>while(<TMPFH>)
>{
>    printf OUTFH $line;
>    read(TMPFH, $line, $length);
>}

You're reading two lines at a time (the implied read in the "<TMPFH>"
statement, and the read command), and only printing the second.

How about:

	while (! eof(TMPFH)) {
		read (TMPFH, $line, 4096);
		print OUTFH $line;
		}

Patrick Wolfe   (pat@kai.com, kailand!pat)
System Programmer/Operations Manager, Kuck & Associates
"Any opinions expressed are my own, not my employers's.
 Please don't call my boss and complain ... again."

lwall@jpl-devvax.JPL.NASA.GOV (Larry Wall) (07/18/90)

In article <8120@pitt.UUCP> al@ee.pitt.edu (Alan Martello) writes:
: I give up.  I want to pipe binary data from one program to another
: while (possibly) filtering it.
: 
: Why doesn't this work and how can it be modified to work?
: 
: ------------------------------------------------------------------------
: ---------
: #!/bin/perl -P
: 
: #
: #  this works (of course) since the shell does the pipe
: #
: system("cat /vmunix | dd of=./vmunix_copy1");
: 
: #
: #  how can I make perl do the same thing explicitly ?
: #  THIS DOESN'T WORK
: #
: open(TMPFH,"cat /vmunix | ");
: open(OUTFH, "| dd of=./vmunix_copy2");
: 
: while(<TMPFH>)
: {
:     printf OUTFH $line;
:     read(TMPFH, $line, $length);
: }
: 
: close(OUTFH);
: close(TMPFH);

It doesn't work because you're thinking of <TMPFH> as a test of whether
there's more in the file.  It does that, but it does it by reading a line's
worth into $_, which the above loop then discards.  You also shouldn't use
printf on a line that might contain spurious % characters--naughty even
in C.  It also looks like you didn't initialize $length.  Also, there's
little point in opening "cat /vmunix |" when you can just open "/vmunix",
but I understand it's just an example.

Say either

    while(<TMPFH>)		# reads file in random sized chunks
    {
	print OUTFH $_;
    }

or

    $length = (stat(TMPFH))[11] || 8192;
    while (read(TMPFH, $line, $length))
    {
	print OUTFH $line;
    }
 
For a binary file, if it's not too big, you might just want to say

    undef $/;		# slurp whole file (requires patchlevel 12)
    $_ = <TMPFH>;
    s/foo/bar/g;	# sample filtration
    print OUTFH $_;

Larry