Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I check (peek) STDIN for piped data in Perl without using select?

I'm trying to handle the possibility that no arguments and no piped data is passed to a Perl script. I'm assuming that if there are no arguments then input is being piped via STDIN. However if the user provides no arguments and does not pipe anything to the script, it will try to get keyboard input. My objective is to provide an error message instead.

Unfortunately, select() is not portable to some non-POSIX systems. Is there another way to do this with maximum portability?

like image 760
C-o-r-E Avatar asked Feb 06 '09 03:02

C-o-r-E


2 Answers

Perl comes with the -t file-test operator, which tells you if a particular filehandle is open to a TTY. So, you should be able to do this:

if ( -t STDIN and not @ARGV ) {
    # We're talking to a terminal, but have no command line arguments.
    # Complain loudly.
}
else {
    # We're either reading from a file or pipe, or we have arguments in
    # @ARGV to process.
}

A quick test reveals this working fine on Windows with Perl 5.10.0, and Linux with Perl 5.8.8, so it should be portable across the most common Perl environments.

As others have mentioned, select would not be a reliable choice as there may be times when you're reading from a process, but that process hasn't started writing yet.

All the best,

Paul

like image 172
pjf Avatar answered Oct 24 '22 17:10

pjf


use POSIX 'isatty';
if ( ! @ARGV && isatty(*STDIN) ) {
    die "usage: ...";
}

See: http://www.opengroup.org/onlinepubs/009695399/functions/isatty.html

Note that select wouldn't be much help anyway, since it would produce false results if the piped info wasn't ready yet. Example:

seq 100000|grep 99999|perl -we'$rin="";vec($rin,fileno(STDIN),1)=1;print 0+select($rin,"","",.01)'
like image 30
ysth Avatar answered Oct 24 '22 17:10

ysth