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

Hi Gurus:
Im writing some perl that will execute an interactive command at some point in the code. The command is proprietary, but functions something like the sqlplus command, ie it pauses while connecting to a db, and gives a prompt. Between executing commands, there is typically a pause in which no input can be issued. Normally, I would use Expect to do this, but the system is in production, and the customer will not let me install new perl modules on it.

I was going to do this....

$|=1; $N_CONS = "/usr/bin/ncons"; open (CONS, "| $N_CONS"); sleep 5; print CONS "config execute test.cfg \n"; sleep 5; print CONS "config save \n"; sleep 5; print CONS "quit \n"; sleep 5; close (CONS);
As I suspected, even with  sleep () between the  print statements, the commands get run too quickly to be processed by the called command. In fact, it generally closes the filehandle before it even gets to run the "quit" piece, leaving the script hanging until I send it a SIGTERM. Setting  $|=1 doesnt help either. Any suggestions?

-chris

Replies are listed 'Best First'.
Re: Interactive Input without Expect.pm
by dragonchild (Archbishop) on May 24, 2004 at 17:08 UTC
    You will be putting new code into production. Is there anything keeping you from cut'n'pasting the code in Expect.pm into your script?

    ------
    We are the carpenters and bricklayers of the Information Age.

    Then there are Damian modules.... *sigh* ... that's not about being less-lazy -- that's about being on some really good drugs -- you know, there is no spoon. - flyingmoose

    I shouldn't have to say this, but any code, unless otherwise stated, is untested

      Ummm.. I hadnt really thought about that. How would I include the module's source into my code? And doesnt Expect require the Tty and Pty modules as well?

      -chris

        You've never looked at the source code of a CPAN module before? Get thee hence to /usr/local/lib/perl5/site_perl/5.8.0/ and read, man!

        More, usefully, you could do the following:

        1. Download the tarball
        2. Unpack it into the distros directory under your home directory
        3. Browse the source (it's in the lib/ directory)

        Yeah, Expect uses IO::Pty and IO::Tty. IO::Pty uses IO::Tty. It looks like they're all PurePerl and that the non-core dependencies stop there.

        As for putting them into your script ... literally cut'n'paste the entire .pm below your source code. Something like:

        #!/usr/local/bin/perl use strict; $|++; # My code here # Do not put any use statements!! You've already "used" the modules package Expect; # blahblahblah package IO::Tty # blahblahblah 1;

        Note: This will bloat the size of your script to about 10k lines. Hope you're paid by the KB! :-)

        Another option would be to bundle Expect and IO-Tty in with your code as a distribution to be installed. Just install those modules in the same directory as your script(s). *shrugs*

        ------
        We are the carpenters and bricklayers of the Information Age.

        Then there are Damian modules.... *sigh* ... that's not about being less-lazy -- that's about being on some really good drugs -- you know, there is no spoon. - flyingmoose

        I shouldn't have to say this, but any code, unless otherwise stated, is untested

Re: Interactive Input without Expect.pm
by perrin (Chancellor) on May 24, 2004 at 17:44 UTC
    Talk some sense into your customer. Forcing you to write your own version of something that already exists in a widely used module will make the system less stable, not more.

    In addition to Expect, you might check out IPC::Run.

Re: Interactive Input without Expect.pm
by Fletch (Bishop) on May 24, 2004 at 17:49 UTC

    Erm, so they want added functionality implemented by your new code, but they don't want to add any other code such as Expect? It sounds more like someone's living in a land of make-believe full of elves, faries, and eskimo</Homer>.

    If there were an existing copy of Expect and it's prereqs installed that would need upgrading then yes I could see an issue; but if it's adding new code you just need to weild the cluebat and explain: "You want X; the quickest way to get X is me using module Y. Otherwise you're going to pay me BIGNUM reproducing what X does off the shelf."

      Yeah, that would be good, except this is a fixed price project, and there are about 100-150 servers that need this script run on them. Im not about to do this. Having to compile/install Tty/Pty/Expect on all of em gives the sysadmins grey hairs. They dont want to install, and thats the excuse they are giving management.

      In any case, Im about to cheat by writing a script from my workstation that uses Expect to ssh to each of the servers, mounts an NFS share which has my original script, executes my script minus the parts that needs Expect, and then runs the Expect parts via ssh. An ugly hack, but it should work ;-)

      -chris

Re: Interactive Input without Expect.pm
by Plankton (Vicar) on May 24, 2004 at 17:58 UTC
    Normally, I would use Expect to do this, but the system is in production, and the customer will not let me install new perl modules on it.
    This reminds me of this node. Why are there so many retards running things?

    Plankton: 1% Evil, 99% Hot Gas.
Re: Interactive Input without Expect.pm
by mifflin (Curate) on May 24, 2004 at 18:11 UTC
    Is your customer balking at installing Expect/IO::Tty... in the standard perl/lib directories (the default) or do they just not want you to use library code?
    If it is the first case can't you install these modules in another area? MakeMaker has options to install modules anywhere. Do a perldoc on ExtUtils::MakeMaker. At first glance you could use the 'LIB' feature...
    perl Makefile.PL LIB=/dir/where/I/want/to/Install
    There may be other features to set to make sure man pages and pod info gets put into the correct areas.
    If you can do this , then all you would have to do is a 'use lib ...' at the top of you program and Expect would be available.
      You could simply write standard SQL scripts and parse the output....
      system ('sqlplus -s /NOLOG @file.sql'); Inside your SQL, set head off feed off ....etc you write spool /script/dir/tmp/file.log; SELECT ..... spool off;
      and open and get the output...if the SQL is simple and fixed. Or you can use DBI/DBD module for oracle.