in reply to Interactive IO with IO::Pipe on Win32

it works fine for non-interactive commands, however input prompts are not displayed until after input has been received. The result is that the user cannot see the prompt and does not know what they are being prompted for, or even that they are being prompted.

Maybe I'm misunderstanding something here but...of course the user doesn't see the prompts, how could they?

The program $cmd in your example will write it's prompts to stdout, and $pipe->reader( $cmd ) runs that command, redirecting it's stdout to a pipe, so that your program can read it.

Just as you don't see the output from dir when you do dir >file, so you are not going to see the prompt from (say) pause when you do pause > junk because it ends up in the file.

C:\test>type junk Press any key to continue . . .

Same thing with your pipe, any prompts from the command will end up going via the pipe into your program. Unless the command was printing to the console via some other filehandle (eg. stderr) or using direct console IO.

Here is a way that might work for you. If you don't have a copy of the tee utility, you can get a Win32 version as a part of UnxTools. You then issue your command as

$pipe->reader( 'yourprog arg arg | tee CON' );

Which will allow the user to see the prompts and respond to them

C:\test>perl -MIO::Pipe -we"$p=IO::Pipe->reader('(pause & dir z)|tee C +ON');@i=<$p>;print qq[Got '$_']for @i" Press any key to continue . . . Volume in drive C has no label. Volume Serial Number is BCCA-B4CC Directory of C:\test File Not Found Got 'Press any key to continue . . . 'Got ' Volume in drive C has no label. 'Got ' Volume Serial Number is BCCA-B4CC 'Got ' 'Got ' Directory of C:\test 'Got ' '

with the caveats that

  1. your program will also receive a copy of the prompts in it's input which you could probably filter out;
  2. The user will also see all the output from the command echo'd on the screen which may or may not be a problem.

What it comes down to is that there is no way for the pipe to know which output (to stdout) from the command is intended for interaction with the user, and what is a part of the final output you wish to capture. This is not a win32 limitation (of it's forking or anything else), you will get the same results on *nix also.

Finally, you may or may not know that IO::File->reader is effectively the same as doing

$pid=open CMD, "$cmd |"; @input = <CMD>;

eg.

C:\test>perl -e"$pid=open CMD,q[(pause & dir z)|tee CON |];@i=<CMD>;pr +int qq[Got '$_']for @i" Press any key to continue . . . Volume in drive C has no label. Volume Serial Number is BCCA-B4CC Directory of C:\test File Not Found Got 'Press any key to continue . . . 'Got ' Volume in drive C has no label. 'Got ' Volume Serial Number is BCCA-B4CC 'Got ' 'Got ' Directory of C:\test 'Got ' '

Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
Lingua non convalesco, consenesco et abolesco. -- Rule 1 has a caveat! -- Who broke the cabal?
"Science is about questioning the status quo. Questioning authority".
In the absence of evidence, opinion is indistinguishable from prejudice.

Replies are listed 'Best First'.
Re^2: Interactive IO with IO::Pipe on Win32
by Anonymous Monk on Feb 14, 2006 at 19:11 UTC
    Hi BrowserUK,

    Thanks for your response. There does seem to be a misunderstanding as I'm having no trouble forwarding output from the command to the console. The only time I have a problem is when the command prompts for input. The prompt will appear on the console, but only after the input has been entered.

      forwarding output from the command to the console.

      By "forwarding" I assume you mean printing the input you receive?

      The prompt will appear on the console, but only after the input has been entered.

      That because you can't print it until you have read it, and you won't be able to read it until readline (in the guise of the diamond operator <$fh>), returns, which it won't until it see a newline.

      As many prompts are printed without a newline so that the users input goes on the same line as the prompt, the text of the prompt will not be dispatched into the pipe until a newline is seen, and that won't happen until the user enters one.

      Given that you appear to be printing everything received from the command, the tee trick I offered would probably work well for you. You just allow tee to do the forwarding and you just gather the output within your program for whatever processing you need to do, rather than echoing it yourself. The only extra step required is to filter the prompt and user input from the datastream.


      Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
      Lingua non convalesco, consenesco et abolesco. -- Rule 1 has a caveat! -- Who broke the cabal?
      "Science is about questioning the status quo. Questioning authority".
      In the absence of evidence, opinion is indistinguishable from prejudice.
        As many prompts are printed without a newline so that the users input goes on the same line as the prompt, the text of the prompt will not be dispatched into the pipe until a newline is seen, and that won't happen until the user enters one.

        I think you hit the nail on the head. For some reason I was thinking that I had the same problem with multi-line prompts (i.e. none of the prompt was visible until after user input). On the contrary, I just tested my script with a program that generates a five line prompt and the entire prompt was visible prior to input.

        I guess I'll have to read from the pipe with sysread or something like it. Thanks for your help!