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

Hi people,

Another STDIN-related question. (I think. :/)

I'm refactoring an app that analyses email messages. I'd like to set up a conditional at the beginning of the script where I can take piped in data if it's available, and do something else if it's not (in this case, go look in an IMAP folder.) In other words, I'd like to be able to call...

./script.pl

...and have my script do its default behavior (use IMAP), or pipe it a message directly...

cat sample.eml | ./script.pl
or
./script.pl < sample.eml

and just deal with sample.eml.

When groping for a handle on understanding the mechanism I need, I simply tried doing this:
if ( <STDIN> ) { print "Got STDIN.\n"; # Look for more STDIN till there's no more. } else { print "Default behavior.\n"; # Go connect to the IMAP server and feed there. }
Of course, when I execute, my script sits there and waits for STDIN. One of those moments where my stupidity becomes painfully obvious to me only after the fact. But I don't know which way to go with this, and I don't know how to search for the answer.

All I know is that I want this program to take what gets offered it, and if nothing is offered, to go do its own thing without sitting around and waiting for a handout.

Any /(help|nudges in the right direction)/ will be much appreciated.

Replies are listed 'Best First'.
Re: Piping input as an option
by dave_the_m (Monsignor) on Jul 04, 2007 at 11:12 UTC
    You could test whether STDIN is attached to a terminal:
    $ perl -le 'print "yes" if -t STDIN' yes $ perl -le 'print "yes" if -t STDIN' < /dev/null $

    Dave.

      perl -le 'print "yes" if -t STDIN'

      Perfect! Thanks, Dave, this is exactly what I was looking for.

      Thank you to all three of you for your suggestions. I'm set now.

      -jkelly

Re: Piping input as an option
by Joost (Canon) on Jul 04, 2007 at 11:14 UTC
Re: Piping input as an option
by whereiskurt (Friar) on Jul 04, 2007 at 13:21 UTC

    jkelly:

    Ahh...this reminds me of an old PBP proverb:

    Interactivity: Don't reinvent the standard test for interactivity.

    Try a little something like this in your code:

    use IO::Interactive qw( is_interactive ); if ( is_interactive() ) { print "Show a prompt?\n"; } else { print "Gobble STDIN.\n"; }

    That's the gist of IO::Interactive . Hopefully you find it helpful/useful (I sure have in the past!)

    By the way, if you peek inside of the code for IO::Interactive, you'll see there are few gotchas that the module addresses that you'd need to address (read: reinvent) to be thorough. I think one of them has to do with piping in a '/dev/null'.

    Kurt

    PS: I swear I'm not a Damian Conway fanboy!

      Thanks to you, Kurt, and citromatik for pushing me in this direction. I'm gonna check it out.

      -jkelly

      PS: Would it be so bad to be a Damian Conway fanboy?

        If being Damian Conway's fanboy is a bad thing then I don't even want to know what good is! :-)

        But, in all seriousness, Perl's best feature is the community. We have people to look up to. We have great minds that aren't afraid to go out on a limb and participate in a community. People share their code, and let other people hack on it.... I'm actually getting emotional over here.

        Best of luck with it!

        Kurt

Re: Piping input as an option
by citromatik (Curate) on Jul 04, 2007 at 11:40 UTC

    You can use IO::Prompt:

    use strict; use warnings; use IO::Prompt; while( prompt "next: " ) { print "You said '$_'\n"; }

    If you save your script as "prompt.pl":

    $ cat > test.txt Hello World ^D $ perl ./prompt.pl < test.txt You said: Hello You said: World $ cat test.txt | perl ./prompt.pl You said: Hello You said: World

    Update: I missed the point. If you want to perform differently if the input is given in a pipe or not, you can use IO::Interactive:

    use strict; use warnings; use IO::Interactive qw(is_interactive); if (is_interactive){ print "interactive\n"; } else { print "piped\n"; }

    If you save this script as "interactive.pl":

    $ perl ./interactive.pl intereactive $ cat test.txt | perl ./interactive.pl piped $ perl ./interactive.pl < test.txt piped

    citromatik

      Good catch. Thanks for your insight.

      -jkelly