On Thu, 29 Sep 2016 01:47:36 -0700 (PDT) DM <subharaj.ma...@gmail.com> wrote:
> Cross-posting this from stackoverflow > <http://stackoverflow.com/questions/39764600/getting-error-back-after-executing-a-shell-script-via-golang> > :- > > I have a simple shell script (named copy.sh) which looks like below:- > > #! /bin/sh > > cp $1 $2 > > I did chmod 777 copy.sh. Never to this: you've just granted full write access to everyone (the last 7). Executables should have 755 or 775 and no more, and that's if you don't care about everyone reading their contents. > 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("\nCopy 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? [...] That's simple: you're confusing exit codes of OS processes [1] with messages they write to their standard output streams [2]. That "cp: /Users/debraj/gotest/temp.txt: Permission denied" is a _message_ the `cp` program run by your script writes to its standard error stream. It then exits with some non-zero exit status indicating failure to do its job. Since that's the last command run by the script, that exit status also becomes the exit status of the whole script. Now the Go runtime machinery which was executing your script waited for its process to terminate, collected its exit code and since it was not zero (indicating success), it generated and returned a non-nil error value. That error value contained the exit code. Now note that Go errors must implement the standard interface which has the name "error" and is defined to be type error interface { func Error() string } and, Error() is what you had called on that error value to obtain its _string representation_ -- basically what the error value's concrete type thinks its values should look like when rendered as text. As you can see, what Error() returns for the error value generated by exec.Command() has no bearing on what the process it were executing output to its standard streams (or elsewhere). It only "knows" about that process' exit status (and may be some other platform-specific information). So, if you want to "grab" what your spawned process had written to its standard streams (or only the error stream) before dying, you need to explicitly capture this information. Now see what you did: 1) A call to os/exec.Command() returned a pointer to a value of type os/exec.Cmd it constructed. 2) You then immediately called Output() on that pointer. So let's see the documentation on the latter: | $ go doc os/exec.Cmd.Output | func (c *Cmd) Output() ([]byte, error) | Output runs the command and returns its standard output. Any | returned error will usually be of type *ExitError. If c.Stderr was | nil, Output populates ExitError.Stderr. So, this function only returns what the process had written to its standard output stream -- not its standard error stream (where error messages usually go). But it also appears to collect what the process writes to its standard error stream if it has not been redirected. OK, by now you should be inspecting the docs on os/exec.Command, os/exec.Cmd and figuring out that the former indeed constructs a value of os/exec.Cmd with its Stderr property left with its default value, nil, which means os/exec.Cmd.Output() indeed should have collected the error stream of your process in the error's value Stderr property. Now please also study the documentation on os/exec.ExitError. There, you can learn that os/exec.Cmd.Output() is smart about collecting the error stream so that it wont grab overlong error outputs of the process. If it's OK for you, you should roll like this: _, err := exec.Command(...).Output() if err != nil { ee, ok := err.(*exec.ExitError) if !ok { return err } // OK, so we really have an instance of ExitError // Now do something with the value of ee.Stderr // which is of type []byte. } You may of course consider other approaches as os/exec allows you to do any sort of things with handling the output streams of the process being executed. To help you further, we'll need more information on what you really want to do. A side note: the shell command language works much like PHP: if any executed command returns an error the script interpreted continues to chug away. If you need to fail as soon as possible always start your scripts with the set -e -u primitive (this also should be done for scripts executed in subshells). 1. https://en.wikipedia.org/wiki/Exit_status 2. https://en.wikipedia.org/wiki/Standard_streams -- You received this message because you are subscribed to the Google Groups "golang-nuts" group. To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.