Simple way to run a command

1,789 views
Skip to first unread message

i3dmaster

unread,
Jun 4, 2011, 11:57:09 PM6/4/11
to golang-nuts
The new exec API simplified a lot in running subprocesses, but yet, I
still can't seem to find the easiest and intuitive way to just run a
command and get the output printed out.

I thought I could just

func main() {
exec.Command("ls", "-la").Run()
}

and get what I was expecting, but hmm... the *Cmd object created by
Command does not specify any IO interfaces. So I have to

cmd := exec.Command("ls", "-la")
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
cmd.Run()

Or

cmd := exec.Command("ls", "-la")
out, err := cmd.CombinedOutput()
if err == nil { fmt.Printf("%s\n", out) }

Am I missing a simpler way to exec a command?

Could we consider add a package level func

func Run(name string, args ...string) os.Error {
cmd := Command(name, args...)
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
cmd.Env = os.Environ()
return cmd.Run()
}

so that clients can just do

exec.Run("ls", "-la") and get the expected behavior? (more or less
like the system() call?)

Thanks!

Dave Cheney

unread,
Jun 5, 2011, 12:30:45 AM6/5/11
to i3dmaster, golang-nuts

Martin Capitanio

unread,
Jun 5, 2011, 1:35:32 AM6/5/11
to golan...@googlegroups.com, i3dmaster
cmd.Run() should probably have this as default setting.

Martin

Rich

unread,
Jun 5, 2011, 12:59:25 PM6/5/11
to golan...@googlegroups.com, i3dmaster
What I did was create my own package that I called 'system'. I plan to add other functions into it as I need them but this simplifies the running of a command.

System.go:
package system


import "exec"
import "os"
import "io/ioutil"
import "strings"

func Exec(bin string, arg string) (retStr string,err os.Error) {
        cmd,err:=exec.LookPath(bin)
        if err != nil {
                return "",err
        }
        if arg != "" {
                arg= cmd + " " + arg
        }
        a:=strings.Split(arg," ",-1)
        c,err := exec.Run(cmd, a,nil, "", exec.DevNull, exec.Pipe, exec.DevNull)
        if err != nil {
                return "",err
        }
        defer c.Close()
        out,_:=ioutil.ReadAll(c.Stdout)
        retStr= strings.TrimRight(string(out),"\n")
        return retStr,nil
}

I created a directory in $GOROOT/src/pkg/system, then copied / modified one of the make files from go:

# Copyright 2009 The Go Authors. All rights reserved.
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.

include ../../Make.inc

TARG=system
GOFILES=\
system.go\

GOFILES+=$(GOFILES_$(GOOS))

include ../../Make.pkg

Once compiled and installed, you just import it and call system.Exec("<program","<arguments")  Here is an example:

package main

import (
"system"
"fmt"
)

func main() {
a,err:=system.Exec("uname","-a")
if err != nil {
fmt.Printf("Error: %v\n",err)
} else {
fmt.Printf("Uname returned: %s\n",a)
}
}

Kyle Lemons

unread,
Jun 5, 2011, 1:20:11 PM6/5/11
to golang-nuts
No guarantees about removing trailing newlines or anything, but eliminating this sort of wrapper is exactly why Run was written.  Your main could be written as:

package main

import (
"exec"
"os"
"log"
)

func main() {
out, err := exec.Command("uname", "-a").Output()
if err != nil {
log.Fatalf("Error: %s", err)
}
os.Stdout.Write(out)
}

Cheers,
--
~Kyle

"Everyone knows that debugging is twice as hard as writing a program in the first place. So if you're as clever as you can be when you write it, how will you ever debug it?" 
— Brian Kernighan

Yongjian Xu

unread,
Jun 5, 2011, 1:50:04 PM6/5/11
to Kyle Lemons, golang-nuts
Not making sense why there is a such goal to "eliminate" this sort of
wrapper. Its trivial to have the API providing such functionality and
save many programmers typing 3-4 lines of code to just trying to run a
command. I could understand maybe the designer wants to give freedom
to the programmers to hook up any IO targets they want, they've
already had options, they could build a Cmd struct and do whatever
they want, but this does not conflict to provide an easy wrapper to do
the most obvious thing for its users.

On Sunday, June 5, 2011, Kyle Lemons <kev...@google.com> wrote:
> No guarantees about removing trailing newlines or anything, but eliminating this sort of wrapper is exactly why Run was written.  Your main could be written as:
> package main
>
>
> import ( "exec"
>
> "os" "log"
>
> )
> func main() {
>
> out, err := exec.Command("uname", "-a").Output()
>
> if err != nil { log.Fatalf("Error: %s", err)
>
> } os.Stdout.Write(out)
>
> }
> Cheers,
> On Sun, Jun 5, 2011 at 9:59 AM, Rich <rma...@gmail.com> wrote:
> What I did was create my own package that I called 'system'. I plan to add other functions into it as I need them but this simplifies the running of a command.
>
>
> System.go:package system
>
> import "exec"
>
> import "os"import "io/ioutil"import "strings"
> func Exec(bin string, arg string) (retStr string,err os.Error) {
>
>         cmd,err:=exec.LookPath(bin)        if err != nil {                return "",err        }        if arg != "" {
>
>                 arg= cmd + " " + arg        }        a:=strings.Split(arg," ",-1)        c,err := exec.Run(cmd, a,nil, "", exec.DevNull, exec.Pipe, exec.DevNull)
>
>         if err != nil {                return "",err        }        defer c.Close()        out,_:=ioutil.ReadAll(c.Stdout)
>
>         retStr= strings.TrimRight(string(out),"\n")        return retStr,nil}
> I created a directory in $GOROOT/src/pkg/system, then copied / modified one of the make files from go:
>
>

> # Copyright 2009 The Go Authors. All rights reserved.# Use of this source code is governed by a BSD-style

Message has been deleted

Kyle Lemons

unread,
Jun 6, 2011, 12:01:20 PM6/6/11
to golang-nuts
This thread is about the new exec API from the latest weekly.
~K

On Mon, Jun 6, 2011 at 8:56 AM, Rich <rma...@gmail.com> wrote:
Kyle -- I like your solution, but my system doesn't have an exec.Command:

exec.go:9: undefined: exec.Command

Is this a new addition to one of the weekly builds?  I also don't see it in the documentation:




Rich

unread,
Jun 6, 2011, 12:10:53 PM6/6/11
to golan...@googlegroups.com, Kyle Lemons
Kyle -- Cool. I had to update my go to the latest weekly build, and now I can eliminate the system package that I built, and just run it like this:

package main

import (
"fmt"
"exec"
        "strings"
)

func main() {
a,err:=exec.Command("uname","-a").Output()
if err != nil { 
Reply all
Reply to author
Forward
0 new messages