如何从System.cmd输出中捕获每一行?

leo*_*eon 5 elixir phoenix-framework

如何从System.cmd其他方法运行命令时捕获在控制台中写入的每一行?

我甚至想要捕获最终结果,但在这种情况下控制台中显示的内容类似于:Cloning into 'myrepo'... remote: Counting objects: 3271, done.并通过通道发送每一行:

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
Run Code Online (Sandbox Code Playgroud)

我没有找到解决方案,有类似的问题,但没有明确的答案:问题问题

aso*_*nge 8

所以,这里有几种方法,我将尝试总结并让您能够理解其他问题中的先前答案.

首先,你应该知道详细处理这些东西,你需要学习如何使用:erlang.open_port/2.您可以传递{:line, max_length}选项以获得每行1条消息.git您看到的输出是写入的内容stderr,您可以传递:stderr_to_stdout重定向,以便每个消息输入1行.您可以循环使用receive直到收到eof消息,并且可以查看文档以获取有关何时eof发出该消息的更多详细信息.

bitwalker在你的第二个链接中的答案将通过一些修改得到你想要的东西:

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
Run Code Online (Sandbox Code Playgroud)

现在,虽然我们可以将stderr重定向到stdout,但其中一个问题是git将检测重定向流并调整相应流的流量.我希望你比较这些调用的输出:

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

这会在流中找到的每个"\n"打印出1条消息.注意所有与\ r \n的垃圾?这就是进步的结果.你可以--progress从args中删除,你只需要获得1或2条无聊线.如果你想获得所有东西,你需要流式传输结果,然后自己分割line-ish输出.

Shell.exec(gitcmd, ["clone","--progress",url], [:stream])
Run Code Online (Sandbox Code Playgroud)

你可以从使用中看到,:stream而不是:line我们会得到所有东西,因为它是从另一方冲洗的.你必须清理悬空\r\n自己,你可能想要计划接收部分线路,但我认为这应该可以帮助你顺利完成旅程.

这是所有关于重定向错误输出到标准输出,但如果你需要实际保留之间的区别stderrstdout,如果你想有能力杀死进程,而不是依赖于它关闭你关闭后stdin,你将不得不依赖在像瓷器这样的东西上管理一个表现良好的过程,为你"管理"另一个过程.