Is there a fairly direct way to get from System.cmd a stream which when enumerated will return the command output line by line?
:into IO.stream()
Just echos output to stdout as it comes in. It seems that I can get what I need by either creating a process to receive output and using receive there, or dropping down to Erlang and using a port directly. But I’m wondering if there is some higher-level support for this which I am missing?
I’m not sure about the context of your requirements. But personally, I always lean towards small and sufficient implementations rather than large and comprehensive ones. From that perspective, a simple Port wrapper is sufficient.
This is the default behaviour of port.
You have to explicitly pass {line, L} option, but this requires more work to be done, as L is a maximum length of line, so you have to deal with :noeol messages.
It is far easier to apply String.split/3 to split the string by \n
Yep. I’ve gone through the source for System.cmd and the documentation for port, and I see how to do it that way. I’m thinking some support in System.cmd for a couple more port options might be useful. For the moment I’ll deal with the “one chunk” return, and circle back to optimizing later–and see if I think it would be useful to make a PR against System.cmd.
I note that L can be 0. Does that imply no limit? Docs don’t say what it means; I will test later when I have time. If it does, that’s ideal for this use.
Gulping millions of lines into a string and then splitting works, but the point of streaming by line is to avoid unnecessarily building a humongous stream.
Gulping millions of lines into a string and then splitting works, but the point of streaming by line is to avoid unnecessarily building a humongous stream.
This is actually how the ports are implemented (and hence System.cmd). Internally, port just reads everything that is available on the stdout buffer and send it as a message to the calling process, it does not wait for the caller to consume. Also, the config {line, L} how the output is delivered to calling process not how it is read into VM. So if your external program producing a lot of output in short amount of time then it still can get accumulated in your beam vm memory irrespective of the line limit config.