On Mon, 16 Jan 2017 13:35:07 -0800 (PST) Deepak Jain <deepuj...@gmail.com> wrote:
> util.ExecuteCommandWithOuput(exec.Command("cp", "-r", "./*.json", > artifact. dir)) > > func ExecuteCommandWithOuput(cmd *exec.Cmd) { > output, err := cmd.Output() > if err != nil { > log.Print("Error executing ", cmd.Args, err) > } > fmt.Print(string(output)) > } > > Output > > 2017/01/16 13:26:35 Error executing [cp -r ./*.json myartifact] exit > status 1 > > Questions > 1. How do i get details of complete error message on failure of cp > command ? I did have err != nill and Print err The os/exec.Command() function constructs an value of type os/exec.Cmd which is a struct type describing the details of an external process to execute. Processes on Unix-like OSes (and Windows) have notions of the standard streams [2]. The "stderr" is where (well-written) programs write their error messages when they encounter a problem preventing them from completing their intended task. Values of the os/exec.Cmd have three fields, Stdin, Stdout and Stderr, which control the standard streams of the process to be executed, and as it happens by default these fields are initialized to nil which means the spawned process will have its standard streams connected to the so-called "null device" (/dev/null on Unices and NUL on Windows), and so its error output will go to nowhere. There are different approaches at handling error output of the external processes. 1. You can connect its Stderr to the Stderr of your running process which is available as os.Stderr, like this: cmd := exec.Command(`cp ...`) cmd.Stderr = os.Stderr and then whatever that `cp` process outputs will end up on the standard error stream of your host process. 2. You can "collect" that output and do something with it. One approach is to exploit the fact pointers to values of type bytes.Buffer implement the io.Writer interface, so you can do var errmsg bytes.Buffer cmd := exec.Command(`cp ...`) cmd.Stderr = &errmsg err := cmd.Run() if err != nil || errmsg.Len() > 0 { log.Fatalf("Failed to copy: %s\n", errmsg.String()) } 3. The CombinedOutput() method of the os/exec.Cmd type provides a way to intelligently collect the outputs--to both the standard output stream and the standard error stream--of the process being executed and present them to you as a combined chunk of bytes. Such collection is done in an intelligent way -- by keeping only a manageable "header" and "trailer" parts of the output to deal with cases where a process spews enormous amounts of data, and you don't intend to process it all, and would be okay with just decorating those collected bits with some error message prefix and so on. > 2. Does exec.Command not support copy of files and recursive copy of > directories ? exec.Command() has nothing to do with copying anything. As its name suggests, it's a tool to execute external processes, and these processes can do anything. The `cp` program is for copying/linking filesystem entities but you could execute FireFox or Apache just as easily. > 3. Any suggestions how i implement copy of files and recursive copy > of directories ? [...] Answered over there at SO [1]. Here's my answer copied from there: ---------------->8---------------- The problem To explain: the so-called "wildcards" are expanded by the shell in which you typically execute command-line commands. That is, when you invoke `cp -r ./*.json dir/`, the shell kicks in, expands *.json by itself—producing a list of names of the files matching that pattern and located in the current directory and pass the cp command a list of such names. So if you have, say, 10 matching files, the actuall call to cp will end up looking like cp -r file1.json file2.json ... dir/ When you pass call `cp ...` directly—without the shell kicking in and expanding that *.json "fileglob" for you, the cp command receives the name of a file "*.json" verbatim and attempts to open it. Since the file named exactly "*.json" supposedly does not exist, `cp` fails and exits. The solutions The first (admittedly lame) solution is to pass a call to cp "through" a shell. That is, turn your call to cp into a shell script and pass it to a shell. The simplest way to do this is to use something like exec.Command(`/bin/sh -c 'cp -r ./*.json manifest'`) This will call a shell `/bin/sh` and pass it the script to execute via its -c command-line option. Another solution is to roll copying yourself using the standard Go library: the functions of the path/filepath package provide support for both expanding fileglobs as the shell would do it and iterating over the entries of a given directory. Using either of these approaches you can build the list of files to copy and/or iterate over them. Then you can use the function os.OpenFile() to open the source and destination files, and io.Copy() to copy the contents between them. ---------------->8---------------- Please, if you ask your question using several venues, make sure to cross-reference between them. 1. http://stackoverflow.com/a/41690953/720999 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.