Jump to content

Console I/O for Child Processes


DaveF
 Share

Recommended Posts

OK, I've got an alpha implementation done for the console standard I/O functions. You can set options so that AutoIt will create pipes that it will connect to the STDOUT, STDERR and (some day) STDIN streams for any child processes that it creates with the Run() function. You can then read from (and some day write to) the pipes sort of like you would from a file. Normal console text messages and console error messages are written separately by the child process on the STDOUT and STDERR streams respectively, and you have the option to capture either or both separately for later reading.

Reading from the pipes removes the characters read from the pipe buffer and makes room for the child process to write more data if needed. If the child needs to write data and there is no room on the pipe, the child will halt in the middle of its write process until room is available, i.e. until AutoIt reads from its end of the pipe. If AutoIt tries to read from its end of the pipe and no characters are available, e.g. the child hasn't written anything yet (or never will), then the read process won't return until there is something to read or the pipe is closed on the child end. This is normal for piped console I/O, it's the way that it works in DOS or UNIX as well as Windows. If it bugs you that much for your script to be halted, an option is available that lets you peek to see if characters are available on the pipe before attempting to read from it.

The implementation works like this:

AutoItSetOption("ProvideRunStdout", 1)

tells AutoIt to create a new pipe and connect it to the STDOUT stream of each new child process created with Run()

$pid = Run(@ComSpec & " /c dir c:\autoexec.bat")

a console window will open for this command, but no text will be visible (unless there's an error) because it's being captured by AutoIt.

$output = ReadStdout($pid, 512)

Read from a redirected STDOUT pipe. The first parameter is for the process ID returned by the Run() function for the child process we wish to read from. The second, optional parameter is for the max number of characters to try to read from the pipe. If the second parameter is not provided the function will read as many characters as are available off the pipe, up to 64k. If fewer characters than the maximum are available then the function reads all the available characters off the pipe and returns the string of characters.

If ReadStdout() is called with an argument of zero in the second parameter the function just peeks into the pipe and returns the number of characters available without reading any characters off the pipe.

You can read from STDERR by setting the ProvideRunStderr option and using the ReadStderr() function.

I've still only got undocumented uglycode, but with the code freeze anyway it couldn't be included in a beta release until the next stable release, so I guess there's no hurry...

If it's OK I'd be glad to post an unofficial EXE and example code in the public file area.

Yes yes yes, there it was. Youth must go, ah yes. But youth is only being in a way like it might be an animal. No, it is not just being an animal so much as being like one of these malenky toys you viddy being sold in the streets, like little chellovecks made out of tin and with a spring inside and then a winding handle on the outside and you wind it up grrr grrr grrr and off it itties, like walking, O my brothers. But it itties in a straight line and bangs straight into things bang bang and it cannot help what it is doing. Being young is like being like one of these malenky machines.

Link to comment
Share on other sites

  • Administrators

  I've still only got undocumented uglycode, but with the code freeze anyway it couldn't be included in a beta release until the next stable release, so I guess there's no hurry...

  If it's OK I'd be glad to post an unofficial EXE and example code in the public file area.

Go for it.

So can you for instance capture the output of say, ping.exe with this?

Link to comment
Share on other sites

Could you also, for instance capture the output of console commands such as dir?

In the past, I've had to do things such as:

RunWait("cmd /c dir > C:\output.txt", "", @SW_HIDE)
$output = FileRead("C:\output.txt", FileGetSize("C:\output.txt"))

If I could grab the output of dir directly without writing to a file, I would be :idiot:

Use Mozilla | Take a look at My Disorganized AutoIt stuff | Very very old: AutoBuilder 11 Jan 2005 prototype I need to update my sig!
Link to comment
Share on other sites

There's a ZIP of the unofficial standard-I/O-aware AutoIt3.exe and a demo script at:

http://www.autoitscript.com/fileman/users/public/DaveF/stdout.zip

I had mistakenly left in a test to prevent capturing output streams when you call the child process with RunWait(), so you'll get a fatal error if you try with this version.

Go for it.

So can you for instance capture the output of say, ping.exe with this?

<{POST_SNAPBACK}>

Sure thing:

AutoItSetOption("ProvideRunStdout", 1)

$foo = Run("ping.exe 66.94.234.13", @SystemDir)

While 1
    $output = $output & ReadStdout($foo)
    If @error = -1 Then ExitLoop
Wend

MsgBox(0, "STDOUT read:", $output)

Yes yes yes, there it was. Youth must go, ah yes. But youth is only being in a way like it might be an animal. No, it is not just being an animal so much as being like one of these malenky toys you viddy being sold in the streets, like little chellovecks made out of tin and with a spring inside and then a winding handle on the outside and you wind it up grrr grrr grrr and off it itties, like walking, O my brothers. But it itties in a straight line and bangs straight into things bang bang and it cannot help what it is doing. Being young is like being like one of these malenky machines.

Link to comment
Share on other sites

Could you also, for instance capture the output of console commands such as dir?

In the past, I've had to do things such as:

RunWait("cmd /c dir > C:\output.txt", "", @SW_HIDE)
$output = FileRead("C:\output.txt", FileGetSize("C:\output.txt"))

If I could grab the output of dir directly without writing to a file, I would be  :idiot:

<{POST_SNAPBACK}>

The demo in the ZIP does just this. Enjoy!

Yes yes yes, there it was. Youth must go, ah yes. But youth is only being in a way like it might be an animal. No, it is not just being an animal so much as being like one of these malenky toys you viddy being sold in the streets, like little chellovecks made out of tin and with a spring inside and then a winding handle on the outside and you wind it up grrr grrr grrr and off it itties, like walking, O my brothers. But it itties in a straight line and bangs straight into things bang bang and it cannot help what it is doing. Being young is like being like one of these malenky machines.

Link to comment
Share on other sites

Implemented STDIN to child process:

http://www.autoitscript.com/fileman/users/public/DaveF/stdio.zip

Try:

AutoItSetOption("ProvideRunStdout", 1)
AutoItSetOption("ProvideRunStdin", 1)

$foo = Run("sort.exe", @SystemDir)

; Write string to be sorted to child sort.exe's STDIN
WriteStdin($foo, "rat" & @CRLF & "cat" & @CRLF & "bat" & @CRLF)
; Calling with no 2nd arg closes the write handle to the STDIN pipe
WriteStdin($foo)

; Read from child's STDOUT and show
MsgBox(0, "Debug", ReadStdout($foo))

Enjoy.

Yes yes yes, there it was. Youth must go, ah yes. But youth is only being in a way like it might be an animal. No, it is not just being an animal so much as being like one of these malenky toys you viddy being sold in the streets, like little chellovecks made out of tin and with a spring inside and then a winding handle on the outside and you wind it up grrr grrr grrr and off it itties, like walking, O my brothers. But it itties in a straight line and bangs straight into things bang bang and it cannot help what it is doing. Being young is like being like one of these malenky machines.

Link to comment
Share on other sites

I tried to control FTP.exe, but I can't get it to send/write the password.

<{POST_SNAPBACK}>

I've seen problems too, with telnet and even @ComSpec & " /c time"

The console window flickers open and then immediately closes. It does this even if you just provide STDOUT without STDIN.

With ftp.exe I at least got some output, which is encouraging.

At work now, can't test more at the moment.

Yes yes yes, there it was. Youth must go, ah yes. But youth is only being in a way like it might be an animal. No, it is not just being an animal so much as being like one of these malenky toys you viddy being sold in the streets, like little chellovecks made out of tin and with a spring inside and then a winding handle on the outside and you wind it up grrr grrr grrr and off it itties, like walking, O my brothers. But it itties in a straight line and bangs straight into things bang bang and it cannot help what it is doing. Being young is like being like one of these malenky machines.

Link to comment
Share on other sites

  • 2 weeks later...

Submitted my final alpha for the child process standard console I/O redirection functionality to Jon yesterday.

It works like:

AutoItSetOption("ProvideRunStdout", 1)
AutoItSetOption("ProvideRunStderr", 1)
AutoItSetOption("ProvideRunStdin", 1)

...turn on redirection for STDOUT, STDERR and STDIN respectively, so that...

$foo = Run("sort.exe", @SystemDir)

...starts the child process SORT.EXE with AutoIt providing/capturing all the I/O that would normally be provided by the keyboard and sent to the console window, and stores the handles for the I/O pipes in an internal object that we can look up using the process ID that was returned ($foo above) by the call to Run(). Knowing that, we can send a string of input to sort with:

WriteStdin($foo, "rat" & @CRLF & "cat" & @CRLF & "bat" & @CRLF)

The particular behavior SORT.EXE is that it doesn't do anything until its STDIN pipe is closed, which we do by calling WriteStdin with no 2nd argument:

WriteStdin($foo)

In this example after the STDIN pipe is closed, SORT does its thing and writes the result to the STDOUT pipe and exits. Because AutoIt still has its handle to the pipe, the data remains until we read it with a call to ReadStdout(). We can then display it:

$bar = ReadStdout($foo)
MsgBox(0, "Debug", $bar)

I tried to make as thin a wrapper as I could around the underlying I/O and not impose any assumptions about ease-of-use on the user. As such, there are some caveats for working with these functions:

- If you try to do a write with WriteStdin() and there's no room in the STDIN buffer, the function will "block" and not return until the child process reads enough characters for the write operation to complete.

- Likewise, if you try to do a read with ReadStdxxx() and there are no characters in the buffer to read, the function will block and not return until there are characters to read.

In both of these cases while AutoIt is waiting for the function in question to return AutoIt is effectively halted, and no processing of hotkeys, GUI messages, etc. is done.

- Console redirection isn't supported with RunAsSet(). In >= NT versions of Windows one must worry about security settings for the pipes and handles; I tried a number of things like setting the security permissions wide open but I still got no results when the child process was called using RunAsSet().

Some "console" apps I've experimented with don't behave predictably if you try to redirect their I/O. Some will exit immediately if you try, TELNET.EXE is an example. Others work OK, like FTP.EXE, but the Password: prompt still gets written to the screen even if you redirect STDOUT and STDERR. I'm sure you can find other examples as well.

Just posted a ZIP of this version at:

http://www.autoitscript.com/fileman/users/public/DaveF/

EDIT: Added download URL.

Edited by DaveF

Yes yes yes, there it was. Youth must go, ah yes. But youth is only being in a way like it might be an animal. No, it is not just being an animal so much as being like one of these malenky toys you viddy being sold in the streets, like little chellovecks made out of tin and with a spring inside and then a winding handle on the outside and you wind it up grrr grrr grrr and off it itties, like walking, O my brothers. But it itties in a straight line and bangs straight into things bang bang and it cannot help what it is doing. Being young is like being like one of these malenky machines.

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...