views:

326

answers:

5

I am trying to create something in Perl that is basically like the Unix tee command. I'm trying to read each line of STDIN, run a substitution on it, and print it. (And eventually, also print it to a file.) This works if I'm using console input, but if I try to pipe input to the command it doesn't do anything. Here's a simple example:

print "about to loop\n";
while(<STDIN>)
{
  s/2010/2009/;
  print;
}
print "done!\n";

I try to pipe the dir command to it like this:

C:\perltest>dir | mytee.pl
about to loop
done!

Why is it not seeing the piped input? (I'm using Perl 5.10.0 on WinXP, if that is relevant.)

+10  A: 

Try:

C:\perltest>dir | perl mytee.pl
codaddict
+1 Nice catch .
Byron Whitlock
hmm... that works, but why do I have to specify it like that?
Jenni
Because you are on windows. On unix, you can put #!/usr/bin/perl at the top of the perl file to tell the shell were perl is located. On windows only .exe and .com files can be executed directly.
Byron Whitlock
Then why did it print "about to loop" and "done"?
Barry Brown
ok, in my case "c:\scripts" is in %PATH%, and ".PL" is in %PATHEXT%. i want to be able to call `foo | mytee` from anywhere, without having to remember that in this one case i need to put a "perl" in front of it and the ".pl" at the end. any suggestions or am i out of luck?
Jenni
@Jenni You can use `pl2bat` to convert your Perl script into a batch file, which Windows will then be happy to pipe through.
ephemient
well i found a workaround. I create a "mytee.bat" file in c:\scripts. that bat file has `@echo off` on first line, and `perl c:\scripts\mytee.pl %1 %2` as the second line. this works--the input gets piped through the bat file to the perl script. Since .bat is before .pl in my PATHEXT makes it so that "mytee" executes "mytee.bat" rather than the perl script.
Jenni
A: 

Well IMHO, perl is poor substitute for sed ;)

dir | sed s/2009/2010/

Byron Whitlock
i simplified the part of my script that is irrelevant to my question.
Jenni
But perl is a good substitute for: `'sed' is not recognized as an internal or external command, operable program or batch file` ;-)
mobrule
+1  A: 

There's nothing wrong with trying to learn by doing, but a quick search of CPAN shows a number of possible solutions for the tee in Perl problem.

For example: PerlIO::Tee.

Telemachus
+5  A: 

Could it be Microsoft KB #321788?

Scripts that contain standard input (STDIN) and standard output (STDOUT) may not work correctly if you start the program from a command prompt and you use a file association to start the script.

zoul
sounds like that is the problem. i've found a workaround involving piping through a bat file then calling the perl executable (see accepted answer). thanks!
Jenni
+1 @zoul I was so busy looking up the information, I did not notice you had already posted the link.
Sinan Ünür
+12  A: 

This is actually a bug in how Windows handles IO redirection. I am looking for the reference right now, but it is that bug that requires you to specify

dir | perl filter.pl

rather than being able to use

dir | filter

See Microsoft KB article STDIN/STDOUT Redirection May Not Work If Started from a File Association:

  1. Start Registry Editor.
  2. Locate and then click the following key in the registry: HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer
  3. On the Edit menu, click Add Value, and then add the following registry value:
    • Value name: InheritConsoleHandles
    • Data type: REG_DWORD
    • Radix: Decimal
    • Value data: 1
  4. Quit Registry Editor.
C:\Temp> cat filter.pl
#!/usr/bin/perl

while ( <> ) {
    print "piped: $_";
}
C:\Temp> dir | filter
piped:  Volume in drive C is MAIN
piped:  Volume Serial Number is XXXX-XXXX
piped:
piped:  Directory of C:\Temp>
piped:
piped: 2010/03/19  03:48 PM              .
piped: 2010/03/19  03:48 PM              ..
piped: 2010/03/19  03:33 PM                32 m.pm
piped: 2010/03/19  03:48 PM                62 filter.pl
Sinan Ünür
thanks sinan, very useful answer. this makes it so i don't need the icky batch file workaround
Jenni
@Jenni The disadvantage, of course, is that you cannot be sure that `InheritConsoleHandles` will have been set on any other computers to which you might deploy your scripts (which is where `pl2bat.bat` comes in). Thank you for accepting my answer.
Sinan Ünür