2016-02-08 13 views
4

如何從System.cmd或通過其他方式運行命令時捕獲在控制檯中寫入的每一行?如何從System.cmd輸出捕獲每一行?

我想即使捕獲最終結果,但什麼是顯示在控制檯在這種情況下,這將是類似於:Cloning into 'myrepo'... remote: Counting objects: 3271, done.和發送經由通道的每一行:

case System.cmd("git", ["clone", "[email protected]:#{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 

我還沒有找到解決辦法,有類似問題但沒有明確的答案:questionquestion

回答

4

因此,這裏有幾個方法,我將嘗試總結一下,並且能夠理解其他問題中的以前的答案。

首先,你應該知道,處理這個東西的細節,你需要學習如何使用: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所有的垃圾?這就是進展情況。你可以從參數中刪除--progress,你只會得到1或2條無聊的線。如果你想獲得所有東西,你需要流式傳輸結果,然後自行分割輸出。

Shell.exec(gitcmd, ["clone","--progress",url], [:stream]) 

您可以使用:stream而不是:line因爲它是被從另一個側面flush'd我們會得到的一切看到的。您必須自己清理懸掛的\r\n,並且您可能希望計劃接收部分線路,但我認爲這應該可以幫助您順利完成旅程。

這是所有關於重定向錯誤輸出到標準輸出,但如果你需要真正留住stderrstdout之間的區別,如果你想有能力殺死進程,而不是依賴於它關閉關閉stdin後,你將不得不依賴諸如porcelain之類的東西來管理一個行爲良好的進程,以便爲您「管理」其他進程。