How to handle certain output from eval_string

It does not. Do it in iex and you will see what is happening.

iex(1)> {result, _} = Code.eval_string("IO.puts('a')")
a
{:ok, []}
iex(2)> IO.puts result
ok
:ok

The {:ok, []} from the first function call is the return value of calling Code.eval_string/3. In this case, you are binding the result variable to the atom :ok.

In the second line, you are printing out the atom :ok, which gets printed as ok. And then we see :ok as the return value of the IO.puts/2 call.