Observe Process while it is running

It seems that the pipe only becomes readable AFTER the process
terminates.

This is a pretty common phenomenon when dealing with pipes. If the child process does client-side buffering, data won’t show up on the parent side of the pipe until the client flushes its buffer.

As the parent, you don’t have direct control over the child’s buffering policy. Some programs have a command-line option to change their behaviour in this regard, although that’s pretty rare. Most programs use the default buffering policy described in the setvbuf man page. If that’s the case then you can implicitly switch the policy by using pseudo-terminal rather than a pipe. See the pty man page for more. It’s not much fun.

As a first step I recommend that you test the program from Terminal using cat. Imagine a tool that prints data to stdout periodically:

% cat main.swift 
import Foundation

func main() {
    while true {
        print(Date.now)
        sleep(1)
    }
}
main()
% swiftc main.swift

If you run it directly from your shell, stdout is connected to your terminal and you see lines of output each second:

% ./main 
2023-03-27 07:55:38 +0000
2023-03-27 07:55:39 +0000
2023-03-27 07:55:40 +0000
^C

Now pipe the output to cat:

% ./main | cat
^C

Here stdout is connect to a pipe and the tool now buffers. If you leave it long enough, you’ll eventually see one giant blob of output.

So, run your tool in this way and see if its log messages show up promptly.

Share and Enjoy

Quinn “The Eskimo!” @ DTS @ Apple

6 Likes