Beefy Boxes and Bandwidth Generously Provided by pair Networks
Think about Loose Coupling
 
PerlMonks  

Need pipe and parameter help

by Todd Chester (Scribe)
on Nov 17, 2016 at 07:27 UTC ( #1176039=perlquestion: print w/replies, xml ) Need Help??
Todd Chester has asked for the wisdom of the Perl Monks concerning the following question:

Dear Perl Monks,

perl-5.16.3-286.el7.x86_64

I seek the following wisdom. I am trying to create a sample .pl script to demonstrate how to:

1) read a pipe and read parameters at the same time, and

2) not hang if the pipe is empty

This is basically the thing I am trying to demonstrate:
ls -al | grep -i xxx
where the grep both reads parameters and the pipe.

This is what I have so far and the resulting errors (I still hang on an empty pipe)

#!/usr/bin/perl use strict; use warnings; my $Pipe= ""; while (<>){ # replaced in Perl 5.22 with "for ( @ARGV )" # Reference: http://www.perlmonks.org/?node_id=1175906 # for ( @ARGV ) { $Pipe .= $_; } print "This was read from the pipe:\n"; print "<$Pipe>\n\n"; print "This was the read from the parameters:\n"; print "<@{ARGV}>\n"; __END__

$ ( echo Hi; sleep 3; echo Bye ) | ./ReadAPipe.pl 1 2 3 4
Can't open 1: No such file or directory at ./ReadAPipe.pl line 9.
Can't open 2: No such file or directory at ./ReadAPipe.pl line 9.
Can't open 3: No such file or directory at ./ReadAPipe.pl line 9.
Can't open 4: No such file or directory at ./ReadAPipe.pl line 9.
This was read from the pipe:
<>

This was the read from the parameters:
<>


Many thanks,
-T

Replies are listed 'Best First'.
Re: Need pipe and parameter help
by tybalt89 (Curate) on Nov 17, 2016 at 07:40 UTC
    #!/usr/bin/perl # http://perlmonks.org/?node_id=1176039 use strict; use warnings; my $Pipe = ''; while(<STDIN>) { $Pipe .= $_; } print "This was read from the pipe:\n"; print "<$Pipe>\n\n"; print "This was the read from the parameters:\n"; print "<@{ARGV}>\n"; __END__

      Thank you!


      $ ( echo Hi; sleep 3; echo Bye ) | ./ReadAPipe.pl a b c
      This was read from the pipe:
      Hi
      Bye


      This was the read from the parameters:
      a b c


      -T

        ./ReadAPipe.pl a b c

        hangs with an empty pipe
        how do I fix that?

Re: Need pipe and parameter help
by Corion (Pope) on Nov 17, 2016 at 08:58 UTC

    Maybe now is a good moment to step back and explain in plain English what you want the script to do.

    From your various replies, it seems to me that you want your script to read from STDIN if there is input piped to it, but not read from STDIN when it is launched interactively.

    The easy approach would be to use the -t test (or even better, -p) to check whether STDIN is connected to an interactive terminal or not.

    In your commented reference to 1175906, you erroneously state that there was a change in 5.22 in the handling of @ARGV resp. while( <> ), but the comments there state that no such change happened between 5.002 and 5.24. You might want to revisit that node and maybe update your comment accordingly.

Re: Need pipe and parameter help
by shmem (Chancellor) on Nov 17, 2016 at 09:22 UTC
    1) read a pipe and read parameters at the same time

    Paramters of the command line are accessible through the @ARGV array.
    Piped input is read from the filehandle STDIN via the "diamond operator" <> or readline. The empty diamond operator is special, since it treats any arguments on the command line as input files, which are attempted to be read before STDIN. (update: If the program is invoked from the terminal and there is no pipe connected to STDIN of the invoked process, its STDIN is connected to the terminal. You can close that STDIN by sending an end-of-file char via the terminal's line discipline, usually typing <Ctrl>-D)

    If you want read from STDIN only, use <STDIN> like so:

    #!/usr/bin/perl my $Pipe= ""; while (<STDIN>){ $Pipe .= $_; } print "This was read from the pipe:\n"; print "<$Pipe>\n\n"; print "This was the read from the parameters:\n"; print "<@ARGV>\n";

    which invoking $ ( echo Hi; sleep 3; echo Bye ) | ./ReadAPipe.pl 1 2 3 4 produces

    This was read from the pipe: <Hi Bye > This was the read from the parameters: <1 2 3 4>
    2) not hang if the pipe is empty

    Except for buffering by the OS, pipes are always empty - this is how pipes work. Writing to a pipe blocks the writer, as long as the reader doesn't read. Reading from the pipe blocks the reader, as long as the writer doesn't write. If the writer closes the pipe, the reader gets end-of-file (eof).
    Thus, an empty pipe in your sense would be a pipe which is opened and closed by the writer without having written anything to it.

    If you want the reader to time out, you might set up an alarm handler

    #!/usr/bin/perl $SIG{ALRM} = sub { warn "waited too long, exiting. This is what I have:\n"; report(); exit; }; alarm(2); # time out after two seconds my $Pipe= ""; while (<STDIN>){ $Pipe .= $_; } report(); sub report { print "This was read from the pipe:\n"; print "<$Pipe>\n\n"; print "This was the read from the parameters:\n"; print "<@ARGV>\n"; }
    waited too long, exiting. This is what I have: This was read from the pipe: <Hi > This was the read from the parameters: <1 2 3 4>

    - note that the Bye line is missing due to timeout - or you could use select or IO::Select which provides a nice interface to select.

    perl -le'print map{pack c,($-++?1:13)+ord}split//,ESEL'
Re: Need pipe and parameter help
by Discipulus (Monsignor) on Nov 17, 2016 at 07:47 UTC
    Hello,

    If I understand you wont something similar to the following:

    #warning windows doublequote! echo ECHO | perl -nle "BEGIN{print qq([@ARGV]);undef @ARGV}print" arg1 + arg2 [arg1 arg2] ECHO

    L*

    PS Follow the the tybalt89 advice (while mine is more a trick): infact @ARGV is different from STDIN see a more detailed post Difference between piped-in and invocation arguments to a Perl script? and a similar one on SO

    In the first Corion wisely point to I/O-Operators

    L*

    There are no rules, there are no thumbs..
    Reinvent the wheel, then learn The Wheel; may be one day you reinvent one of THE WHEELS.
Re: Need pipe and parameter help
by Todd Chester (Scribe) on Nov 17, 2016 at 13:51 UTC

    Thank you all for the help.

    Figured it out.

    To error is human. To really screw things up required a computer!

    Perl 5: how to read rom a pipe and command line parameter at the same time:

    PeadPipe.pm

    package ReadPipe; require Exporter; use strict; use warnings; use diagnostics; # use diagnostics "-verbose"; use Term::ReadKey qw ( ReadKey ReadMode ); # our @ISA = qw( Exporter ); use Exporter qw(import); our @EXPORT = qw(); # symbols to be exported by default (space- +separated) our $VERSION = 0.01; our @EXPORT_OK = qw( ReadPipe ); # Refernece: https://metacpan.org/pod/Term::ReadKey # ReadMode MODE [, Filehandle] # # Takes an integer argument, which can currently be one of the foll +owing values: # # 0 Restore original settings. # 1 Change to cooked mode. # 2 Change to cooked mode with echo off. # (Good for passwords) # 3 Change to cbreak mode. # 4 Change to raw mode. # 5 Change to ultra-raw mode. # (LF to CR/LF translation turned off) # # Or, you may use the synonyms: # # restore # normal # noecho # cbreak # raw # ultra-raw

    Thank you all for the help.

    Figured it out.

    To error is human. To really screw things up required a computer!

    Perl 5: how to read rom a pipe and command line parameter at the same time:

    PeadPipe.pm

    package ReadPipe; require Exporter; use strict; use warnings; use diagnostics; # use diagnostics "-verbose"; use Term::ReadKey qw ( ReadKey ReadMode ); # our @ISA = qw( Exporter ); use Exporter qw(import); our @EXPORT = qw(); # symbols to be exported by default (space- +separated) our $VERSION = 0.01; our @EXPORT_OK = qw( ReadPipe ); # Refernece: https://metacpan.org/pod/Term::ReadKey # ReadMode MODE [, Filehandle] # # Takes an integer argument, which can currently be one of the foll +owing values: # # 0 Restore original settings. # 1 Change to cooked mode. # 2 Change to cooked mode with echo off. # (Good for passwords) # 3 Change to cbreak mode. # 4 Change to raw mode. # 5 Change to ultra-raw mode. # (LF to CR/LF translation turned off) # # Or, you may use the synonyms: # # restore # normal # noecho # cbreak # raw # ultra-raw # # # ReadKey MODE [, Filehandle] # # Takes an integer argument, which can currently be one of the foll +owing values: # # 0 Perform a normal read using getc # -1 Perform a non-blocked read # >0 Perform a timed read sub ReadPipe () { # if data is not present in the pipe (STDIN), return an empty sting # if data is present, read until an EOF is detected, then return th +e # string, less the EOF mark my $Pipe = ""; my $Key = ""; ReadMode 4; # Turn off controls keys if ( defined ( $Key = ReadKey ( -1, \*STDIN ) ) ) { $Pipe = $Key; while ( <STDIN> ) { $Pipe .= $_ }; # reads until EOF detected } ReadMode 1; # Reset tty mode before exiting chomp ( $Pipe ); # print STDERR "\$Pipe = <$Pipe>\n"; return $Pipe; }

    ReadAPipe.pl

    #!/usr/bin/perl # Note: check out Pause.pm for reading empty keys use lib '/home/linuxutil'; use strict; use warnings; use ReadPipe qw ( ReadPipe ); my $Pipe= ""; # while (<STDIN>){ $Pipe .= $_; } # hangs if pipe is empty $Pipe = ReadPipe::ReadPipe (); print "This was read from the pipe:\n"; print "<$Pipe>\n\n"; print "This was the read from the parameters:\n"; print "<@{ARGV}>\n"; __END__
    $ ( echo Hi; sleep 3; echo Bye ) | ./ReadAPipe.pl a b c This was read from the pipe: <Hi Bye> This was the read from the parameters: <a b c> ./ReadAPipe.pl a b c This was read from the pipe: <> This was the read from the parameters: <a b c>
    # # # ReadKey MODE [, Filehandle] # # Takes an integer argument, which can currently be one of the foll +owing values: # # 0 Perform a normal read using getc # -1 Perform a non-blocked read # >0 Perform a timed read sub ReadPipe () { # if data is not present in the pipe (STDIN), return an empty sting # if data is present, read until an EOF is detected, then return th +e # string, less the EOF mark my $Pipe = ""; my $Key = ""; ReadMode 4; # Turn off controls keys if ( defined ( $Key = ReadKey ( -1, \*STDIN ) ) ) { $Pipe = $Key; while ( <STDIN> ) { $Pipe .= $_ }; # reads until EOF detected } ReadMode 1; # Reset tty mode before exiting chomp ( $Pipe ); # print STDERR "\$Pipe = <$Pipe>\n"; return $Pipe; }

    ReadAPipe.pl

    #!/usr/bin/perl # Note: check out Pause.pm for reading empty keys use lib '/home/linuxutil'; use strict; use warnings; use ReadPipe qw ( ReadPipe ); my $Pipe= ""; # while (<STDIN>){ $Pipe .= $_; } # hangs if pipe is empty $Pipe = ReadPipe::ReadPipe (); print "This was read from the pipe:\n"; print "<$Pipe>\n\n"; print "This was the read from the parameters:\n"; print "<@{ARGV}>\n"; __END__
    $ ( echo Hi; sleep 3; echo Bye ) | ./ReadAPipe.pl a b c This was read from the pipe: <Hi Bye> This was the read from the parameters: <a b c> ./ReadAPipe.pl a b c This was read from the pipe: <> This was the read from the parameters: <a b c>

      Please tidy up that response, it is badly formatted.

      $ ( echo Hi; sleep 3; echo Bye ) | ./ReadAPipe.pl a b c
      This was read from the pipe:
      <Hi
      Bye>
      
      This was the read from the parameters:
      
      
      
      ./ReadAPipe.pl a b c
      This was read from the pipe:
      <>
      
      This was the read from the parameters:
      
      

      Saving your (cleaned up) ReadPipe.pm to a sensible location and running your ReadAPipe.pl, I get:

      qwurx [shmem] ~> ( echo Hi; sleep 3; echo Bye ) | ./ReadAPipe.pl a b c This was read from the pipe: <Hi Bye> This was the read from the parameters: <a b c> qwurx [shmem] ~> ./ReadAPipe.pl a b c This was read from the pipe: <> This was the read from the parameters: <a b c>

      I suspect that the code / result you posted isn't consistent (version mismatch?)

      Please note that the value returned requireing your ReadPipe.pm (which is invoked by use) is the number of elements contained in @EXPORT_OK - which might, or might not, be intended. You should be aware of this side-effect. If your module read

      ... our @EXPORT_OK = qw( ReadPipe ); my $foo; ...

      then loading the module would fail, since the value computed from my $foo is undefined.

      perl -le'print map{pack c,($-++?1:13)+ord}split//,ESEL'

        > Please tidy up that response, it is badly formatted.

        Thank you for the tidy up. The formatting used on this form is *obnoxious*. Are there any plans to move to a more user friendly format?

        My last post I copied and pasted from the source section of Komposer. What a pain in the neck!

        My original solution with the messy formatting would not respond properly to
        (sleep 3; echo bye) | ReadAPipe.pl

        The last post cleaned that up

        Many thanks,
        -T

Re: Need pipe and parameter help
by Todd Chester (Scribe) on Nov 18, 2016 at 20:33 UTC
    Sharma over on comp.lang.perl.misc figured this out for me.
    Thank you all for the help.

    #!/usr/bin/perl use strict; use warnings; chomp(my $Pipe = ( ! -t \*STDIN ) ? do{local $/; &lt;STDIN&gt;} : q{}) +; print "This was read from the pipe:\n&lt;$Pipe&gt;\n\n"; print "These are the list of parameters:\n&lt;@ARGV&gt;\n"; __END__



    $ ReadAPipe3.pl This was read from the pipe: <> These are the list of parameters: <> $ ReadAPipe3.pl 1 2 3 This was read from the pipe: <> These are the list of parameters: <1 2 3> $ echo abc | ReadAPipe3.pl 1 2 3 This was read from the pipe: <abc> These are the list of parameters: <1 2 3> $ (sleep 3; echo abc ) | ReadAPipe3.pl 1 2 3 This was read from the pipe: <abc> These are the list of parameters: <1 2 3> $ echo abc | ReadAPipe3.pl This was read from the pipe: <abc> These are the list of parameters: <> $ sleep 3 | ReadAPipe3.pl 1 2 3 This was read from the pipe: <> These are the list of parameters: <1 2 3>

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://1176039]
Approved by Discipulus
help
Chatterbox?
[Discipulus]: śledzie!! the only sweet my father in law eat

How do I use this? | Other CB clients
Other Users?
Others examining the Monastery: (6)
As of 2017-11-21 11:05 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    In order to be able to say "I know Perl", you must have:













    Results (297 votes). Check out past polls.

    Notices?