I'm trying to use an external process which reads the STDIN, and writes to STDOUT.
I want to write the equivalent of this in Elixir, without using an external library or wrapper script:
$ echo foo | nkf
foo
i.e. send data to nkf on stdin, and get the converted result back from nkf's stdout, knowing that it has finished processing the stream.
I was trying to do this with ports, but the problem is a single sent message can be returned in multiple received messages, so there's no way to tell when the end of the message has been reached (simplified example, "foo" is a whole file in reality):
iex(1)> port = Port.open({:spawn, "nkf -u"}, [:binary])
#Port<0.7>
iex(2)> Port.command(port, "foo")
true
iex(3)> flush
{#Port<0.7>, {:data, "fo"}}
{#Port<0.7>, {:data, "o"}}
:ok
How can I get the same bash pipe behaviour with Ports in Elixir?
The beam does not currently provide a way to close the stream to the process and wait for the stream from the process to finish sending. Using ports, closing the port will also close the stream from the external process, even if the process has not finished sending data. Due to this, it is not currently possible to do using only built-in features - it's necessary to enlist the help of external tools like porcelain or erlexec.