leon February 2016

How to capture each line from System.cmd output?

How to capture each line written in console when run commands from System.cmd or by other approach?

I want even capture final results but what is displayed in console in this case it will be similar to: Cloning into 'myrepo'... remote: Counting objects: 3271, done. and send each line via channels:

case System.cmd("git", ["clone", "git@github.com:#{vault}/#{repo}.git"], cd: repo) do
  {results, 0} ->
    Myapp.Endpoint.broadcast("app:setup", "new:line", results)
  {_, code} ->
    raise RuntimeError, "`git clone` failed with code #{code}"
end

I haven't found solution, there was similar issues but without clear answer: question or question

Answers


asonge February 2016

So, there are a couple approaches here, and I'm going to try to sum up and have you be able to make sense of the previous answers in the other questions.

First of all, you should probably know that handling this stuff in detail, you need to learn how to use :erlang.open_port/2. You can pass {:line, max_length} to the options to get 1 message per line. The output from git that you are seeing is stuff being written to stderr, and you can pass :stderr_to_stdout to redirect that so they come in 1 line per message. You can loop using receive until you receive an eof message, and you can see the docs for more details on when that eof message will be emitted.

bitwalker's answer in your second link will get you what you want with some modification:

defmodule Shell do
  def exec(exe, args, opts \\ [:stream]) when is_list(args) do
    port = Port.open({:spawn_executable, exe}, opts ++ [{:args, args}, :binary, :exit_status, :hide, :use_stdio, :stderr_to_stdout])
    handle_output(port)
  end

  def handle_output(port) do
    receive do
      {^port, {:data, data}} ->
        IO.inspect(data) # Replace this with the appropriate broadcast
        handle_output(port)
      {^port, {:exit_status, status}} ->
        status
    end
  end
end

Now, while we can redirect stderr to stdout, one of the problems here is that git will detect a redirected stream and adjust how much it streams accordingly. I want you to compare the output of these calls:

gitcmd = System.find_executable("git")
Shell.exec(gitcmd, ["clone","--progress",url], [{:line, 4096}])

This prints out 1 message for each "\n" it finds in the stream. Notice all that junk with \r? That's how the progress comes out. You can rem

Post Status

Asked in February 2016
Viewed 1,956 times
Voted 6
Answered 1 times

Search




Leave an answer