Reading output from external program in stdout

I am trying to use Julia to read messages sent to me through xmpp using go-sendxmpp. By following the readme of this package, I can successfully use the terminal to listen to all messages sent to me through:

PS C:\Users\user\xmpp> .\go-sendxmpp.exe --file="./config" --listen
2022-07-15T21:51:09+02:00 user@server: hello world!

So every time a message is sent to me, it writes the message on the stdout, as described in the documentation of the app.

I would like to write a Julia script that:

  1. Catches each line (message) as a string,
  2. Does something to the string e.g. split it into time and payload,
  3. Waits for the next string and repeats the loop.

The overall goal is to send commands to via the xmpp to my computer that Julia executes (I cannot use Genie or Oxygen in this case). I have attempted to solve this myself, but I just cannot get Julia to read the output :confused: Here is my (last) attempt:

b = `go-sendxmpp -f config --listen`
open(b, "w", stdout) do io 
   for ln in readlines(io)
      println(split(ln, " "))
   end
end

I have tried many different variations of this, but (if it doesn’t error), it just ignores the Julia code and prints out the full line, e.g.

2022-07-15T21:51:09+02:00 user@server: hello world!

Does anybody know how I can catch the messages one by one?

If you’re reading from the program output, it should be

open(b, "r", stdout)

Also, make sure the program does write to stdout not stderr.

1 Like

Ah, okay, I changed it to open(b, "r", stdout) but now nothing gets printed when send messages to the account. I confirmed that messages actually come through by running run(b) and then it prints to the repl. I am pretty sure it sends to the stdout because the docs say so, but also I changed the IO to stderr and that did not fix it either :confused:

Try change readlines to readline? The former will not return until reaching eof of an IO buffer.

1 Like

Awesome! That partially fixes it :slight_smile: Now I have:

b = `go-sendxmpp -f config --listen`
open(b, "r", stdout) do io 
   for ln in readline(io)
      println(ln)
   end
end

which outputs individual characters for the first message (which is no problem, I can just join the characters if I write messages with a delimiter to separate individual messages from each other):

2
0
2
2
...
w
o
r
l
d
!

However, when I send another message I get this error:

ERROR: IOError: open(do): broken pipe (EPIPE)
Stacktrace:
 [1] open(::var"#5#6", ::Cmd, ::String, ::Vararg{Any}; kwargs::Base.Pairs{Symbol, Union{}, Tuple{}, NamedTuple{(), Tuple{}}})
   @ Base .\process.jl:404
 [2] open(::Function, ::Cmd, ::String, ::Base.TTY)
   @ Base .\process.jl:393
 [3] top-level scope
   @ REPL[2]:1

This seems to work for me.

# `b` is some `Cmd` object
open(b, "r", stdout) do io
   while !eof(io)
       println(readuntil(io, '\n'))
   end
end

But I don’t understand why the readline version didn’t work.

1 Like

It works! Thank you very much for helping me, I really appreciate it :slight_smile:

The loop iterates over the Chars in the string returned by readline. It calls readline once when entering the loop.

1 Like