duanpuqi9965
2016-09-29 08:00
浏览 234
已采纳

通过Golang执行Shell脚本后找回错误

I have a simple shell script (named copy.sh) which looks like below:-

#! /bin/sh

cp $1 $2

I did chmod 777 copy.sh.

I have a golang code which executes the above shell code:-

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("
Copy Successful - %v")
}

The above code is showing be the below output:-

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

But the error I receive from shell script looks like below:-

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

Can someone let me know how how can I get the same error message that is returned by the shell script?

If I don;t do chmod 777 copy.sh and the file has permission as below:-

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

Then the golang code gives the output as given by the shell script. Can some also let me know why this is behaving like this?

I am on

  • Golang 1.7
  • Mac OS X 10.11.4

图片转代码服务由CSDN问答提供 功能建议

我有一个简单的shell脚本(名为 copy.sh ),如下所示: -

 <代码>#!  / bin / sh 
 
cp $ 1 $ 2 
   
 
 

我做了 chmod 777 copy.sh

我有一个执行以上shell代码的golang代码:-

 包main 
 
import(
“ fmt” 
“ os / exec” \  n)
 
func main(){
 _,err:= exec.Command(“ / Users / debraj / copy.sh”,“ /Users/debraj/temp.txt”,“ / Users / debraj / gotest  /").Output()
 if err!= nil {
 fmt.Println(“无法执行命令” + err.Error())
 return 
} 
 fmt.Printf(“ 
复制成功 -%v“)
} 
   
 
 

上面的代码显示为以下输出:-

   jabongs-MacBook-Pro-4:src debraj $去运行copyerr.go 
无法执行命令退出状态1 
jabongs-MacBook-Pro-4:src debraj $ 
   
 
  

但是我从shell脚本收到的错误如下所示:-

  jabongs-MacBook-Pro-4:〜debraj $ ./copy.sh / Users / debraj  /temp.txt / Users / debraj / gotest / 
cp:/Users/debraj/gotest/temp.txt:权限被拒绝
   
 
 

有人 让我知道如何获取由shell脚本返回的错误消息?

如果不这样做,请不要执行 chmod 777 copy.sh 和 该文件具有以下权限:-

  jabongs-MacBook-Pro-4:〜debraj $ ls -la copy.sh 
-rw-r--r--  1个debraj员工21 Sep 29 13:28 copy.sh 
   
 
 

然后,golang代码给出了shell脚本给出的输出。 有些人还可以让我知道为什么这样吗?

我在

  • Golang 1.7 \ n
  • Mac OS X 10.11.4
  • 写回答
  • 关注问题
  • 收藏
  • 邀请回答

1条回答 默认 最新

  • duanbai5348 2016-09-29 13:28
    已采纳

    Alrighty! So the problem at its core is that you have two different places that you can get an error:

    1. When exec.Command().Output() can't run your shell script at all (because it doesn't have permissions in this case), and
    2. When your shell script itself runs, but returns an error code (because the last line run in the script is an error).

    In the first case, you should get something reasonable in err because Go itself got a well-defined system error when trying to do something (which failed immediately). In the second case, Go was able to run your script, but it had output (that you're ignoring) and an return code (in this case, the exit code of the last thing executed by your script). Since the output could have literally been anything at all (including megabytes and megabytes of nonsense text), Go takes the lazy way out and just returns the status code. This, IMHO, is the right thing to do, given the rampant abuse of stderr by basically everyone.

    Plus, your script (if modified slightly) could actually return an error code without displaying an error message at all!

    That said, if you want to see the actual error information from your script, do one of the following:

    // 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
    ", err.Error())
        return
    }
    

    or:

    // 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
    ", err.Error())
        return
    }
    

    ...or you can go fancier and use StderrPipe() and just read the last line or similar. Really, there are a bunch of ways to skin this particular cat (since cmd.Stderr can be any io.Writer, you could easily write nearly any handler -- including one that parses the stream looking for root causes, etc etc).

    Something to consider is that Output() and CombinedOutput() as used will display stuff only when the script is completely done running. This can be a serious UI problem with long-running scripts, as it means that any user monitoring what's going on will see a big, fat load of nothing while processing is happening. Using StdoutPipe() and StderrPipe() is likely preferable, as you can parse/interpret (or just display) output as it happens. Of course, if you can guarantee that your script won't run for more than a few seconds or that it won't be monitored by a human, who cares?

    If you want to explore how to display output as the script runs, the example for StdoutPipe() is a pretty good place to start.

    打赏 评论

相关推荐 更多相似问题