#!/usr/bin/perl # # shell_select [-t timeout] [-[rwe] fd[,fd]...]... # # Wait for the given file descriptor(s), to be ready for read/write # # This program will wait for at least one of the given file descriptors to be # ready for processing in some way, then report those that are ready, in # a format that the shell can use to assign to variables "$rd_ready", # "$wr_ready" and "$ex_ready", for handling by the shell script. # # It also will report the resulting "$errno" variable and the readable string # form "$errstr". The "$errno" is also used as the commands exit value. # # If a timout is provided it will exit even if no file descriptors are ready. # Use 0 to poll. # # Options: -t time timeout in seconds if still waiting # -r fd,fd,... read input on these file descriptors # -w fd,fd,... write data on these file descriptors # -e fd,fd,... exceptional condition on these # # Example output (for "eval") # # Example Usage, waiting for 3 input streams... # # # Read input from any of three sources # eval $( shell_select -r 11,12,13 ) # if [ "$errno" -ne 0 ]; then # echo >&2 "select error: \"$errstr\" -- ABORTING" # exit 10 # fi # case ",$rd_ready," in # *,11,*) read -r -t 0 <&11 input1 ;; # *,12,*) read -r -t 0 <&12 input2 ;; # *,13,*) read -r -t 0 <&13 input3 ;; # esac # # Also see the "bc" calculator example, linked from... # https://antofthy.gitlab.io/software/#shell_select # ### # # Anthony Thyssen 8 June 2011 # use strict; use warnings; use FindBin; my $PROGNAME = $FindBin::Script; use IO::Select; sub Usage { print STDERR "$PROGNAME: ", @_, "\n" if @_; @ARGV = ( "$FindBin::Bin/$PROGNAME" ); # locate script file while( <> ) { next if 1 .. 2; last if /^###/; last unless /^#/; s/^#$//; s/^# //; last if /^$/; print STDERR "Usage: " if 3 .. 3; print STDERR; } print STDERR "For Options use --help\n"; exit 10; } # convert file descriptors to IO select masks my $rd_select = new IO::Select; my $wr_select = new IO::Select; my $ex_select = new IO::Select; # Option handling... my $timeout=undef; # no timeout by default &Usage() unless @ARGV; while( $_ = shift ) { /t/ && do { $timeout = shift; next }; /r/ && do { $rd_select->add( split(/[^\d]+/, shift) ); next }; /w/ && do { $wr_select->add( split(/[^\d]+/, shift) ); next }; /e/ && do { $ex_select->add( split(/[^\d]+/, shift) ); next }; &Usage( "Unknown or Bad Option \"$_\"\n" ); } Usage( "$PROGNAME: Unknown argument \"$ARGV[0]\"\n" ) if @ARGV; # debugging #print "# Timeout = ", defined $timeout ? $timeout : "undef", "\n"; #print "# Read FD Count = ", $rd_select->count(), "\n"; #print "# Read FD List = ", join(", ", $rd_select->handles()), "\n"; #print "# Write FD Count = ", $wr_select->count(), "\n"; #print "# Write FD List = ", join(", ", $wr_select->handles()), "\n"; #print "# Excpt FD Count = ", $ex_select->count(), "\n"; #print "# Excpt FD List = ", join(", ", $ex_select->handles()), "\n"; # --------------------------------------------------------------- # This is the HEART of the script my ($rd_ready, $wr_ready, $ex_ready ) = IO::Select->select( $rd_select, $wr_select, $ex_select, $timeout); # --------------------------------------------------------------- print "rd_ready='", defined $rd_ready ? join(",", @$rd_ready ) : "", "'\n" if $rd_select->count; print "wr_ready='", defined $wr_ready ? join(",", @$wr_ready ) : "", "'\n" if $wr_select->count; print "ex_ready='", defined $ex_ready ? join(",", @$ex_ready ) : "", "'\n" if $ex_select->count; # error report # typically "Bad file descriptor" (9) when a given file desc has closed print "errno=", $!+0, "\n"; print "errstr='$!'\n"; exit $!;