os.Args[0] bug on Mac with go run?

679 views
Skip to first unread message

John Hare

unread,
Apr 29, 2016, 4:03:04 PM4/29/16
to golang-nuts

So is the value of os.Args[0] correct here? 

Why am I getting a temp dir when running via go run?



$ go version

go version go1.6.2 darwin/amd64


$ pwd

/Users/hare/go/src/testgetwd


$ cat testgetwd.go 

package main


import (

        "fmt"

        "os"

        "path/filepath"

)


func main() {

        fmt.Printf("os.Args[0]: %s\n", os.Args[0])


        fmt.Printf("PWD: %s\n", os.Getenv("PWD"))


        wd, _ := os.Getwd()

        fmt.Printf("Getwd(): %s\n", wd)


        ap, _ := filepath.Abs(filepath.Dir(os.Args[0]))

        fmt.Printf("filepath.Dir(os.Args[0]): %s\n", ap)

}


$ go build testgetwd.go


$ ./testgetwd 

os.Args[0]: ./testgetwd

PWD: /Users/hare/go/src/testgetwd

Getwd(): /Users/hare/go/src/testgetwd

filepath.Dir(os.Args[0]): /Users/hare/go/src/testgetwd


$ go run ./testgetwd.go 

os.Args[0]: /var/folders/bb/ywkhzdf517ngn683g3c5l50c0000gn/T/go-build525038303/command-line-arguments/_obj/exe/testgetwd

PWD: /Users/hare/go/src/testgetwd

Getwd(): /Users/hare/go/src/testgetwd

filepath.Dir(os.Args[0]): /var/folders/bb/ywkhzdf517ngn683g3c5l50c0000gn/T/go-build525038303/command-line-arguments/_obj/exe


 


Output on Linux seems has similar issue:


$ ./testgetwd 

os.Args[0]: ./testgetwd

PWD: /home/jh9/go/src/testgetwd

Getwd(): /home/jh9/go/src/testgetwd

filepath.Dir(os.Args[0]): /home/jh9/go/src/testgetwd


$ go run testgetwd.go 

os.Args[0]: /tmp/go-build149397783/command-line-arguments/_obj/exe/testgetwd

PWD: /home/jh9/go/src/testgetwd

Getwd(): /home/jh9/go/src/testgetwd

filepath.Dir(os.Args[0]): /tmp/go-build149397783/command-line-arguments/_obj/exe



The docs are a bit sparse!

var Args []string

Args hold the command-line arguments, starting with the program name. 



Note: I've got another app where Getwd() returns the temp path also (haven't figured out what's different with that one yet).


Anyone able to enlighten me on this? 

What should I be using to reliably get the working directory?

James Bardin

unread,
Apr 29, 2016, 4:15:26 PM4/29/16
to golang-nuts


On Friday, April 29, 2016 at 4:03:04 PM UTC-4, John Hare wrote:


Anyone able to enlighten me on this? 


"go run" is a convenience function to compile its arguments into a temp location, execute the binary, and clean up. 

 

What should I be using to reliably get the working directory?


John Hare

unread,
May 6, 2016, 2:08:54 PM5/6/16
to golang-nuts
Understood. I guess what I was getting at is asking why isn't "go run" doing something to 
cause os.Args[0] to report the executable where the user would expect it to be (in my case 
/Users/hare/go/src/testgetwd) vs. the random temp dir it chooses to build stuff in.

I haven't taken the time to pin down for sure what changed but my code was working just 
fine using os.Args[0] to find my config file (/Users/hare/go/src/conf/app.conf). Either something
changed with one of the more recent go versions (or the beego package I'm using changed how
they're locating the config file).

kennyl...@gmail.com

unread,
May 6, 2016, 2:28:59 PM5/6/16
to golang-nuts
It doesn't do anything about it because that's not how the command-line arguments work. It would have to compile the binary with a magic os package that lies about os.Args to patch it up, or move the binary to your local folder to change it. go test also runs the binary from "elsewhere".

However, it is your expectations that are wrong, not go run's behaviour. os.Args[0] show the location of the binary. If you want the binary in a specific location, use go build/go install and put it there. Also, using the location of the binary to find files is generally a bad idea. You could use it as a convenience feature, but even then it's on the magical side. Just trying to open "app.conf" where the binary is started is a more normal thing to do, and you should always provide a config flag to set the location of the config file. You can also use that with go run (go run whatever.go -config over/there.conf).

Note that while os.Getwd() gives you the current working directory, all your paths are relative to cwd by default. ioutil.ReadFile(filepath.Join(os.Getwd(), "app.conf")) and ioutil.ReadFile("app.conf") will give you the same results.

Also note that os.Args is not generated by Go, but just passed on from whatever started the application, and os.Getwd() translates to a system call. It's your shell and OS that's responsible for the values.

Best regards,
Kenny
Reply all
Reply to author
Forward
0 new messages