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

I have an app that's essentially an interactive shell, and i'd like to:

Now, i can simply invoke and pass control by using system(), got that advice from the helpful folks in the chatterbox (thanks again guys):
system("./SHELL"); print "by the time you see this, you'll have exited the shell";
but i need to enter specific commands INTO the shell before the user can enter anything themselves...this may take an OS-dependant trick, but thats ok because im only using this on the one specific OS (debian 3.1).

i figured it needs to be something along the lines of the following, but these dont quite work:

#invokes SHELL, then waits until termination of console #to call CMD...not what i need system("./SHELL\nCMD\n"); #invokes the SHELL, enters command into SHELL, #then terminates SHELL before user can do anything system("./SHELL<<EOC\nCMD\nEOC\n");
perhaps i need to somehow drop commands into the terminal's input buffer before i invoke the app? i wouldnt even know where to begin to do that though.

__________
Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.
- Terry Pratchett

Replies are listed 'Best First'.
Re: Invoking, issuing commands to, and passing control to an interactive shell...
by Paladin (Vicar) on Jan 19, 2006 at 17:32 UTC
    You may want to take a look at the Expect module.
Re: Invoking, issuing commands to, and passing control to an interactive shell...
by pileofrogs (Priest) on Jan 19, 2006 at 17:39 UTC

    To do what you want, you pretty much have to abandon system() and get into running the sub-command with filehandles attached to the sub-command's STDIN/STDOUT/STDERR. ....

    ... dig ... dig ... dig....

    Check out perlipc, IPC::Open2 and IPC::Open3 for more about that.

    No chance you can pass the inital info to the sub-process as arguments, is there? That would make it really simple.

    Anyone out there got a better idea?

    --Pileofrogs

    Update:

    Woah... there were no replies when I started typing...

    paladin's recommendation about Expect is probably a better solution than mine, though you should still read perlipc.

Re: Invoking, issuing commands to, and passing control to an interactive shell...
by zentara (Cardinal) on Jan 19, 2006 at 19:50 UTC
    You can use IPC::Open3 or a "piped open" , to open your shell, then print commands to it, by printing to the filehandle. There are plenty of examples around, like:
    my $pid=open3(\*IN,\*OUT,0,'/bin/sh'); # print to and read from IN and OUT #
    or
    open(CHILD, "| ./myscript 2>&1") or die "Can't open: $!"; print CHILD "mycommand\n";

    There is alot of fine tuning that you need to do depending on the shell you are opening, like whether you need to print a newline after each command.


    I'm not really a human, but I play one on earth. flash japh
Re: Invoking, issuing commands to, and passing control to an interactive shell...
by linuxlouis (Initiate) on Jan 19, 2006 at 17:31 UTC
    I have an initial question. Could you use an "xterm" as opposed to your "SHELL?" To xterm you can pass arguments, such as commands that will be executed, as in: xterm -e program_name system("/your/path/to/xterm \-e program_name"); i may be able to help more if, i knew better what you're trying to do.
      what i meant by "interactive shell" is that it's a program that, when called, sits at a kind of prompt, waiting for specific commands. its not an actual system shell like bash, its used for interfacing with a specific daemon, so i need to use this particular app.

      __________
      Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.
      - Terry Pratchett

Re: Invoking, issuing commands to, and passing control to an interactive shell...
by EvanK (Chaplain) on Jan 19, 2006 at 18:37 UTC
    Heh....I was afraid that I'd have to do some kind of "mediating" between the user and the app...There's no way to just force the command into the input buffer so the app will see it?

    __________
    Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.
    - Terry Pratchett

      Instead of 'the app' let's use fdisk.

      From a Perl program, you can call fdisk and then feed commands at fdisk and wait for what fdisk has to say about it, look at that, and feed some more. This way you can, for instance, partition a drive from a Perl program (assuming you have the rights to do that).

      If you don't expect anything afterwards from 'the app' then just feed it your initial stuff and that's it, go do something else.

      As pointed at in other replies, use Expect. You can find it on CPAN. It's basically like this:

      - launch your app

      - wait for its prompt (timeout-controlled)

      - feed your app some string

      The pipe/IPC approach either handmade or using CPAN IPC modules is also very interesting, but if you just want to get on with it and do somethign else, then use Expect.

(DUPE) Re: Invoking, issuing commands to, and passing control to an interactive shell...
by linuxlouis (Initiate) on Jan 19, 2006 at 17:35 UTC

    I have an initial question. Could you use an "xterm" as opposed to your "SHELL?"

    To xterm you can pass arguments, such as commands that will be executed, as in: xterm -e program_name

    system("/your/path/to/xterm \-e program_name");

    i may be able to help more if, i knew better what you're trying to do.

Re: Invoking, issuing commands to, and passing control to an interactive shell...
by toma (Vicar) on Jan 21, 2006 at 07:12 UTC
    I do this sort of thing with POE. The POE::Wheel modules are worth a look.

    It should work perfectly the first time! - toma