2016-09-29 63 views
-1

執行shell腳本後,得到錯誤後,我有一個簡單的shell腳本(名爲copy.sh),它看起來象下面這樣: -通過Golang

#! /bin/sh 

cp $1 $2 

我做chmod 777 copy.sh

我有執行上述殼代碼golang代碼: -

package main 

import (
    "fmt" 
    "os/exec" 
) 

func main() { 
    _, err := exec.Command("/Users/debraj/copy.sh", "/Users/debraj/temp.txt", "/Users/debraj/gotest/").Output() 
    if err != nil { 
     fmt.Println("Failed to execute command " + err.Error()) 
     return 
    } 
    fmt.Printf("\nCopy Successful - %v") 
} 

上面的代碼被表示爲下面的輸出: -

jabongs-MacBook-Pro-4:src debraj$ go run copyerr.go 
Failed to execute command exit status 1 
jabongs-MacBook-Pro-4:src debraj$ 

但錯誤我從外殼腳本接收看起來像下面: -

jabongs-MacBook-Pro-4:~ debraj$ ./copy.sh /Users/debraj/temp.txt /Users/debraj/gotest/ 
cp: /Users/debraj/gotest/temp.txt: Permission denied  

有人可以讓我知道我怎麼能得到相同的錯誤信息噸帽子是由shell腳本返回的?

如果我不;噸做chmod 777 copy.sh和文件有權限如下: -

jabongs-MacBook-Pro-4:~ debraj$ ls -la copy.sh 
-rw-r--r-- 1 debraj staff 21 Sep 29 13:28 copy.sh 

然後golang代碼使輸出的shell腳本給出。有人可以讓我知道爲什麼這是這樣的行爲?

我對

  • Golang 1.7
  • 的Mac OS X 10.11.4
+5

混合輸出代替輸出會不會更好?你忽略了stderr。 – lofcek

回答

2

Alrighty!因此,在其核心的問題是,你有兩個不同的地方,你可以得到一個錯誤:

  1. 當exec.Command()輸出()不能在所有運行shell腳本(因爲它不」。在這種情況下沒有權限),並且當你的shell腳本本身運行但是返回一個錯誤代碼(因爲在腳本中運行的最後一行是一個錯誤)時

在第一種情況下,您應該在err中得到一些合理的結果,因爲Go本身在嘗試執行某些操作時會收到明確的系統錯誤(立即失敗)。在第二種情況下,Go能夠運行你的腳本,但它有輸出(你忽略)和一個返回代碼(在這種情況下,腳本執行的最後一件事的退出代碼)。由於輸出可能完全是任何東西(包括兆字節和兆字節的無意義文本),Go採用懶惰的方式,只是返回狀態碼。這個,恕我直言,是正確的做法,因爲基本上每個人都猖獗地踐踏stderr。

另外,你的腳本(如果稍微修改)實際上可以返回一個錯誤代碼而不顯示錯誤信息!

這就是說,如果你想看到你的腳本實際的錯誤信息,請執行下列操作之一:

// Display everything we got if error. 
output, err := exec.Command(...).CombinedOutput() 
if err != nil { 
    fmt.Println("Error when running command. Output:") 
    fmt.Println(string(output)) 
    fmt.Printf("Got command status: %s\n", err.Error()) 
    return 
} 

或:

// Display just the stderr if an error occurs 
cmd := exec.Command(...) 
stderr := &bytes.Buffer{} // make sure to import bytes 
cmd.Stderr = stderr 
err := cmd.Run() 
if err != nil { 
    fmt.Println("Error when running command. Error log:") 
    fmt.Println(stderr.String()) 
    fmt.Printf("Got command status: %s\n", err.Error()) 
    return 
} 

...或者你可以更有興趣並使用StderrPipe()並只讀最後一行或類似內容。真的,有很多方法可以爲這個特定的cat蒙皮(因爲cmd.Stderr可以是任何io.Writer,你可以輕鬆地編寫幾乎任何處理程序 - 包括分析流查找根本原因的處理程序等)。

需要考慮的一件事是Output()和CombinedOutput()所使用的將僅在腳本完全運行時顯示東西。對於長時間運行的腳本來說,這可能是一個嚴重的UI問題,因爲這意味着任何監視正在發生的事件的用戶在處理過程中都會看到一大堆沒有任何東西。使用StdoutPipe()和StderrPipe()可能更可取,因爲您可以在輸出發生時解析/解釋(或僅顯示)輸出。當然,如果你能保證你的腳本不會超過幾秒鐘,或者它不會被人監控,誰在乎呢?

如果您想要了解如何在腳本運行時顯示輸出,StdoutPipe()的例子是一個很好的開始。

+0

謝謝你這麼好的解釋。 – tuk