如何从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
答案 0 :(得分:7)
所以,这里有几种方法,我将尝试总结并让你能够理解其他问题中的先前答案。
首先,您应该知道详细处理这些内容,您需要学习如何使用: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
现在,虽然我们可以将stderr重定向到stdout,但其中一个问题是git将检测重定向流并调整相应流的流量。我希望你比较这些调用的输出:
gitcmd = System.find_executable("git")
Shell.exec(gitcmd, ["clone","--progress",url], [{:line, 4096}])
这会在流中找到的每个“\ n”打印出1条消息。注意所有与\ r \ n的垃圾?这就是进步的结果。你可以从args中删除--progress
,你只需要获得1或2条无聊线。如果你想得到所有东西,你需要流式传输结果,然后自己按行输出。
Shell.exec(gitcmd, ["clone","--progress",url], [:stream])
您可以看到使用:stream
代替:line
,我们将获得所有内容,因为它是从另一方刷新的。您必须自己清理悬空\r
和\n
,并且您可能想要计划接收部分线路,但我认为这可以帮助您顺利完成旅程。
这完全是关于将stderr重定向到stdout,但是如果你需要实际保留stderr
和stdout
之间的差异,并且你想要能够杀死进程,而不是依赖它关闭stdin
后关闭,您将不得不依赖porcelain之类的东西来管理一个表现良好的流程,为您“管理”其他流程。