SPUG: shell script event loops + wrapping shell utilities

Tim Maher tim at consultix-inc.com
Sun Apr 21 14:24:42 CDT 2002


A message to the SPUG-list from lists at dansanderson.com follows; but first,
a brief message from our sponsor! 8-}

        * * * * * * * * * * * * * * * * * * * * * * * * * * * *
        This message was an attempted post from a SPUG member
        using an address other than the one that was
        subscribed. As a service to the list, for a short
        time, I will periodically scan my in-box for such
        "bounced" messages, and re-post them. However, I won't
        be willing to do this forever, so SPUGsters should
        make sure they know what address they're subscribed
        under, and henceforth use that address when posting
        (perhaps by faking it, by using mutt's "my_hdr"
        directive). This is the price we have paid for
        eradicating SPAM from our list (touch wood!), and I
        think you'll agree it's been worth it!

        So everybody please take care to post from the
        correct address!  If you don't know what address you
	subscribed under, get in touch with me and I'll attempt
	to help you determine it.

	======================================================
	|  Tim Maher                   tim at timmaher.org      |
	|  SPUG Founder & Leader       spug at seattleperl.org  |
	|  Seattle Perl Users Group    www.seattleperl.org   |
	======================================================

       
* * * * * * * * * * * * * * * * * * * * * * * * * * * *

If you're on a *nix system, I recommend using Exceed for this kind of
thing.  Tcl configured, but it's not too hard.  There's an O'Reilly book
for it and everything.

Not to discourage a discussion on the subject, I'd very much like to know
how to do this efficiently in Perl.

-- Dan

On Thu, 18 Apr 2002, dancerboy wrote:

> So, I wanted to add some minor functionality to a couple of shell
> programs (telnet and ftp, specifically) and the simplest way seemed
> to be simply to wrap them in a Perl script, i/e simply make a Perl
> script that opens the program, and pipes input from the terminal
> (keystrokes) through to the program, and passes characters output
> from the program back to the terminal -- occasionally adding some
> extra keystrokes of its own (the added functionality) but mostly just
> acting as a "bidirectional pipe" between the program and the terminal.
>
> Here is the main wrapper part of the ftp version of the script
> (greatly stripped-down for clarity):
>
> ____________________________
> #!/usr/bin/perl
>
> use strict;
> use Fcntl;
> use IPC::Open3;
>
> $| = 1;
>
> my $from_term;
> my $from_shell;
> my $pipe_error;
>
> open(TTY, "+</dev/tty") or die "no tty: $!";
> fcntl( TTY, F_SETFL, O_NONBLOCK );
>
> my $pid = open3( \*TO_SHELL, \*FROM_SHELL, \*SHELL_ERR,
>          'ftp -v strangelight.com'
> );
>
> fcntl( FROM_SHELL, F_SETFL, O_NONBLOCK );
> fcntl( SHELL_ERR, F_SETFL, O_NONBLOCK );
>
> my $oldfh = select(FROM_SHELL); $| = 1; select($oldfh);
> $oldfh = select(SHELL_ERR); $| = 1; select($oldfh);
> $oldfh = select(TTY); $| = 1; select($oldfh);
>
> $SIG{PIPE} = sub { ++$pipe_error; };
>
> while ( not $pipe_error ) {
>                  while( defined( $from_term = getc(TTY) ) ) {
>                          print TO_SHELL $from_term;
>                  }
>                  while( defined( $from_shell = getc(FROM_SHELL) ) ) {
>                          print $from_shell;
>                  }
>                  while( defined( $from_shell = getc(SHELL_ERR) ) ) {
>                          print $from_shell;
>                  }
> }
>
> __END__
>
> Now, I have two questions.
>
> My first question is, admittedly, one of those "I could probably
> figure it out on my own but I'm lazy so I'll ask the folks on SPUG
> instead" questions:
>
> While my script works fairly well as-is, it's a real processor hog,
> as you can probably guess.  All of those getc() calls are
> non-blocking, so even when there's no input or output to process, the
> main while() loop still keeps executing over and over again, doing
> absolutely nothing as fast as it possibly can.  What's the
> best/simplest way to tell Perl to "go to sleep, but wake up as soon
> as something interesting happens"?
>
> My second question is one I've banged my head on for a while and
> haven't been able to figure out at all:
>
> Even with setting $|=1 on all the open pipes, I still don't always
> get my I/O flushed promptly -- in particular, the responses I read
> back from FROM_SHELL seem often to be one or two lines behind what I
> should be getting. (My work-around has been to send a no-op command
> like 'pwd', the response to which usually forces the lines that I
> want to see out of the buffer.)  What else can I do to get my pipes
> "piping hot" (as the perldocs say)?
>
> -jason
>
>  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
>      POST TO: spug-list at pm.org       PROBLEMS: owner-spug-list at pm.org
>       Subscriptions; Email to majordomo at pm.org:  ACTION  LIST  EMAIL
>   Replace ACTION by subscribe or unsubscribe, EMAIL by your Email-address
>  For daily traffic, use spug-list for LIST ;  for weekly, spug-list-digest
>      Seattle Perl Users Group (SPUG) Home Page: http://seattleperl.org
>

 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
     POST TO: spug-list at pm.org       PROBLEMS: owner-spug-list at pm.org
      Subscriptions; Email to majordomo at pm.org:  ACTION  LIST  EMAIL
  Replace ACTION by subscribe or unsubscribe, EMAIL by your Email-address
 For daily traffic, use spug-list for LIST ;  for weekly, spug-list-digest
     Seattle Perl Users Group (SPUG) Home Page: http://seattleperl.org




More information about the spug-list mailing list