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

Hello fellow monks,
UPDATE:Thank you to all who replied. I got it working now. Unfortunately the ancient system I am running does not have Expect on it. I have been unsuccesful in previous attempts to get the sysadmins to add stuff for me. I know I *could* install it in my own directory (done that before too), but moot's suggestion works without having to do that.
Thanks again to everyone.

I am having a little trouble figuring something out and I would appreciate any help you guys can give.

I am trying to put together a perl script to run a variety of different daily checks that I need to run at work. There are several different tools that I need to execute. All but one of them will accept and argument as input, (it is written in C and I don't have the source code to modify). When I call "comparepass.exe" it responds with a list of valid files to check. I already know the name of the file I want to check so I don't really need the list, but with no command line arguments available, I can't override this action.

I know in Net::Telnet, I can issue a command, then use  $prev = $obj->prompt($matchop); to change the prompt and issue another command.

If I use system("comparepass.exe") or @response=`comparepass.exe`; It simply executes the command without giving me a chance to change the prompt or anything and give a secondary input. I know there has to be a way to do this in perl, but I can't find it in my searching, any help would be greatly appreciated.

20050219 Edit by castaway: Changed title from 'Interacting with unix shell'

Replies are listed 'Best First'.
Re: Interacting with a child process
by friedo (Prior) on Feb 10, 2005 at 03:45 UTC
    I'm not exactly sure what you mean by "change the prompt." If you simply need to send command line arguments to the programs you're executing, you can do that both with system (but note the differences between specifying the command as a string vs. as a list) or with backticks. If you need to interact with the program and respond to its prompts for information, it's probably a job for Expect.
Re: Interacting with a child process
by moot (Chaplain) on Feb 10, 2005 at 03:45 UTC
    Would Expect be of any use? or open()? perhaps something like this?

    open CMD, "|comparepass.exe"; print CMD "Some command here\n"; ... close CMD
    Assuming of course that comparepass.exe actually supports input..
      This is exactly what I needed, I new it was something simple, thanx!
Re: Interacting with a child process
by greenFox (Vicar) on Feb 10, 2005 at 03:44 UTC

    I've never used the Perl version but I think what you are wanting is expect.

    --
    Do not seek to follow in the footsteps of the wise. Seek what they sought. -Basho

Re: Interacting with a child process
by graff (Chancellor) on Feb 10, 2005 at 05:32 UTC
    If you know in advance what character data you're going to feed to the program after it starts running, and you don't need to capture its output to a variable inside your perl script, a pipeline open would be easiest:
    open( PIPE, "| comparepass.exe" ); print PIPE "some_file.name\n"; close PIPE;
    Of course, since the child process does generate output, this might cause some trouble if you don't redirect it somewhere -- just add " > junkfile.name" after the name of the program in the open statement. (This might not be a bad be a good idea if you want your script to read the program's output after it runs.)

    <update> if you really are running the program on a unix system, and you really don't need the stuff that the program spits out, redirect like this:  &> /dev/null (that will send both stdout and stderr to the bitbucket). </update>

    If you know you need to capture the output from the program for use in your script, the next easiest thing to try is IPC::Open2. With that, you get two file handles, one to send input to the program, and the other to read its output.

    If you don't know what input you'll give to the program until you get its initial "menu" output, and the program was written in such a way that its output ends up being buffered when its stdout is not a terminal, then you'll need to use expect.

Re: Interacting with a child process
by Errto (Vicar) on Feb 10, 2005 at 04:11 UTC
    If what you need is to launch a program and write to its standard input while reading from its standard output, you can use IPC::Open2 or IPC::Open3 if you also need standard error. Be sure to set autoflush on the filehandle you are writing to, and be sure that the program you are calling also flushes its standard output. Otherwise you will get a deadlock.
Re: Interacting with a child process
by DrHyde (Prior) on Feb 10, 2005 at 10:43 UTC
    You say this is about interacting with the Unix shell, but your executable's name ends in .exe. While this isn't impossible, it does lead me to suspect that things are not quite as they seem! Are you running a Windows application on Unix under some emulation? That may lead to all kinds of "fun" with I/O.
      It really is a C executable written for the ancient HPUX that we are still running. When they compiled it ages ago, the named it .exe.