348

In nodejs I use __dirname . What is the equivalent of this in Golang?

I have googled and found out this article http://andrewbrookins.com/tech/golang-get-directory-of-the-current-file/ . Where he uses below code

_, filename, _, _ := runtime.Caller(1)
f, err := os.Open(path.Join(path.Dir(filename), "data.csv"))

But is it the right way or idiomatic way to do in Golang?

Jonathan Hall
  • 75,165
  • 16
  • 143
  • 189
ekanna
  • 5,462
  • 8
  • 28
  • 31
  • this is not an answer for your question but you may cache the path to a global var (your file location can not be changed while running :) ) not to run os.open again and again each time your code runs – oguzalb Aug 30 '13 at 16:14
  • You should pass `0`, not `1`, to `runtime.Caller()`. – fiatjaf Feb 24 '17 at 14:43
  • 7
    `runtime.Caller(0)` will give you the path of the source file, like `$GOPATH/src/packagename/main.go`. The other answers in this thread are trying to return the path of the executable (like `$GOPATH/bin/packagename`). – fiatjaf Feb 24 '17 at 14:50
  • You're assuming the program is running from a file... – Jonathan Hall Jul 19 '17 at 23:12
  • 1
    Possible duplicate of [Go: find the path to the executable](https://stackoverflow.com/questions/12090170/go-find-the-path-to-the-executable) – Jocelyn Jul 24 '17 at 09:37

18 Answers18

419

EDIT: As of Go 1.8 (Released February 2017) the recommended way of doing this is with os.Executable:

func Executable() (string, error)

Executable returns the path name for the executable that started the current process. There is no guarantee that the path is still pointing to the correct executable. If a symlink was used to start the process, depending on the operating system, the result might be the symlink or the path it pointed to. If a stable result is needed, path/filepath.EvalSymlinks might help.

To get just the directory of the executable you can use path/filepath.Dir.

Example:

package main

import (
    "fmt"
    "os"
    "path/filepath"
)

func main() {
    ex, err := os.Executable()
    if err != nil {
        panic(err)
    }
    exPath := filepath.Dir(ex)
    fmt.Println(exPath)
}

OLD ANSWER:

You should be able to use os.Getwd

func Getwd() (pwd string, err error)

Getwd returns a rooted path name corresponding to the current directory. If the current directory can be reached via multiple paths (due to symbolic links), Getwd may return any one of them.

For example:

package main

import (
    "fmt"
    "os"
)

func main() {
    pwd, err := os.Getwd()
    if err != nil {
        fmt.Println(err)
        os.Exit(1)
    }
    fmt.Println(pwd)
}
Community
  • 1
  • 1
Intermernet
  • 18,604
  • 4
  • 49
  • 61
  • 3
    This is current process working directory. In nodejs it is equivalent to process.cwd() http://nodejs.org/api/process.html#process_process_cwd – ekanna Aug 30 '13 at 16:31
  • 2
    Ok, I see the distinction. Of you're after the location of the binary in the filesytem (rather than the current working directory) I think that `runtime.Caller` is the closest you'll get to "idiomatic" – Intermernet Aug 30 '13 at 16:35
  • 3
    'Released February 2017'? It seems time machine has been invented and we have members posting from the future. It is nice to know a future version will have reliable cross platform method, In the meantime we have to stick to currently available solutions. – ljgww Jan 13 '17 at 08:14
  • 2
    @ljgww Sorry, I'll take my Delorean and go home :-) I updated my answer in advance because I'd only just seen that upcoming feature and figured I'd forget to update the answer later on. – Intermernet Jan 15 '17 at 12:53
  • Fully understand & :) Meditation: Language tense constructs are tricky with time travel. If you specify future tense, when future comes it will become past. We are at the crossroad: shall we write future, then edit in the future, or simply use past tense and wait for future to happen. Future is tricky too, as it may not happen in this parallel universe. – ljgww Jan 16 '17 at 07:18
  • 1
    Edited with `path/filepath.Dir` because `path.Dir` only works with forward slashes (Unix style) as directory separators. – Jocelyn Jul 24 '17 at 08:11
  • This gives me somthing like "/tmp/go-build2363999292/b001/exe/" – Eric Burel Jan 31 '23 at 13:55
  • 1
    @EricBurel This is probably because you're using `go run` instead of `go build` and then running the executable. `go run` will build the executable in a temporary location and then delete it afterwards. It's great for rapid prototyping, but it will give you this result. Try running `go build` and then running the executable. It isn't really any slower. – Intermernet Feb 06 '23 at 10:54
  • The old answer works for me, but not the new one – Paolo Jun 26 '23 at 14:03
259

This should do it:

import (
    "fmt"
    "log"
    "os"
    "path/filepath"
)

func main() {
    dir, err := filepath.Abs(filepath.Dir(os.Args[0]))
    if err != nil {
            log.Fatal(err)
    }
    fmt.Println(dir)
}
Gustavo Niemeyer
  • 22,007
  • 5
  • 57
  • 46
  • 2
    Is it possible for there to be an error here? If so, what would the error be, just out of curiosity? – Jeff Escalante Jun 30 '14 at 15:59
  • Also, it should be noted that this fails when running a program with `go run xxx.go`, where if you substitute in the filename from runtime as stated in the question it works. – Jeff Escalante Jul 01 '14 at 15:51
  • It works just as well with `go run`. Naturally, `go run` will build and execute the file somewhere, rather than executing the source code, so it'll print that location. – Gustavo Niemeyer Jul 02 '14 at 13:03
  • 4
    Doesn't work for me https://play.golang.org/p/c8fe-Zm_bH - os.Args[0] does not necessarily contain the abs path. – zupa Feb 13 '15 at 11:43
  • 6
    It actually works even if os.Args[0] does not contain the abs path. The reason the playground result is not what you expected is because it is inside a sandbox. – Gustavo Niemeyer Jul 21 '15 at 13:51
  • This outputs Temporary path. Not Current Path. Maybe version issue. C:\Users\ati\AppData\Local\Temp\go-build362545898\command-line-arguments\_obj\ex e – atilkan Dec 07 '15 at 16:58
  • 50
    **This is not a reliable way**, see the answer about using **osext** as this was implementation that worked with all of our clients on various OSs. I had implemented code using this method but it seems to not be very reliable and many users complained of bugs that caused by this method choosing the wrong path for the executable. – JD D Jan 12 '16 at 15:38
  • In which cases does this fail? – Kugel Mar 13 '16 at 13:39
  • 8
    Got the same result as emrah using Go 1.6 on Windows (got path of temp folder instead of source file folder). To get the path of your source file's folder without using any external dependency, use a slighly modified version of the OP's code: `_, currentFilePath, _, _ := runtime.Caller(0)` `dirpath := path.Dir(currentFilePath)` (note the `runtime.Caller(0)` instead of `runtime.Caller(1)`) – TanguyP Mar 13 '16 at 13:41
  • @Kugel: On Unix-systems, if the executable is found somewhere in PATH and not started directly (e.g. ./exe) – schieferstapel Dec 16 '16 at 14:19
  • This surely fails if the program was run through a symlink? – Timmmm Jun 27 '18 at 09:18
  • A problem with this solution: this uses `os.Args`, i.e. this is creating a dependency over `os.Args`, which restricts it for getting the path of files in other modules in the application. – Amit Upadhyay Sep 28 '19 at 12:53
  • Its giving me some thing like this "/tmp/go-build246453201/b001/exe" – Ashish Tiwari Mar 21 '20 at 15:24
  • it doesn't work for me, the path is `/tmp/go-build2006237892/b001/exe` – Xb74Dkjb Jan 15 '22 at 04:28
  • @Xb74Dkjb This is probably because you're using `go run` instead of `go build` and then running the executable. `go run` will build the executable in a temporary location and then delete it afterwards. It's great for rapid prototyping, but it will give you this result. Try running `go build` and then running the executable. It isn't really any slower. – Intermernet Feb 06 '23 at 10:51
71

Use package osext

It's providing function ExecutableFolder() that returns an absolute path to folder where the currently running program executable reside (useful for cron jobs). It's cross platform.

Online documentation

package main

import (
    "github.com/kardianos/osext"
    "fmt"
    "log"
)

func main() {
    folderPath, err := osext.ExecutableFolder()
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println(folderPath)
}
Dobrosław Żybort
  • 1,424
  • 12
  • 11
  • 14
    This is the only answer that produced the expected results for me both on Windows and on Linux. – DannyB Oct 21 '14 at 20:37
  • 3
    This works fine until you'd like to use it with `go run main.go` for local development. Not sure how best to get around that without building an executable beforehand each time. – Derek Dowling Jan 14 '16 at 01:37
  • 1
    Sorry I don't know how to make it work with `go run`. This binaries are put in temporary folder each time. – Dobrosław Żybort Jan 18 '16 at 12:15
  • 2
    @DerekDowling a way would be first doing a `go install`, then running `go build -v *.go && ./main`. The `-v` would tell you which files are being built. Generally, I've found that the time different between `go run` and `go build` is tolerable if I've already run `go install`. For windows users on powershell, the command will be `go build -v {*}.go && ./main.exe` – kumarharsh Sep 06 '16 at 11:58
  • Since this will return `$GOPATH/bin/`, why not use `$GOPATH/bin/`? – fiatjaf Feb 24 '17 at 14:49
  • @DerekDowling If you want it to work with "go run" (and built executable as well) then simply use `_, callerFile, _, _ := runtime.Caller(0)` `executablePath := filepath.Dir(callerFile)` instead – Jocelyn Jul 24 '17 at 09:17
  • @Jocelyn I think the problem is instead how to have something universal working in all scenarios – Christophe Vidal Mar 27 '20 at 16:25
38

I came from Node.js to Go. The Node.js equivalent to __dirname in Go is:

_, filename, _, ok := runtime.Caller(0)
if !ok {
    return errors.New("unable to get the current filename")
}
dirname := filepath.Dir(filename)

Some other mentions in this thread and why they're wrong:

  • os.Executable() will give you the filepath of the currently running executable. This is equivalent to process.argv[0] in Node. This is not true if you want to take the __dirname of a sub-package.
  • os.Getwd() will give you the current working directory. This is the equivalent to process.cwd() in Node. This will be wrong when you run your program from another directory.

Lastly, I'd recommend against pulling in a third-party package for this use case. Here's a package you can use:

package current

// Filename is the __filename equivalent
func Filename() (string, error) {
    _, filename, _, ok := runtime.Caller(1)
    if !ok {
        return "", errors.New("unable to get the current filename")
    }
    return filename, nil
}


// Dirname is the __dirname equivalent
func Dirname() (string, error) {
    filename, err := Filename()
    if err != nil {
        return "", err
    }
    return filepath.Dir(filename), nil
}

Note that I've adjusted runtime.Caller(1) to 1 because we want to get the directory of the package that called current.Dirname(), not the directory containing the current package.

Matt
  • 22,224
  • 25
  • 80
  • 116
13

if you do it like this :

dir, err := filepath.Abs(filepath.Dir(os.Args[0]))
if err != nil {
    log.Fatal(err)
}
fmt.Println(dir)

you will get the /tmp path when you are running program using some IDE like GoLand because the executable will be saved and run from /tmp

i think the best way for getting the currentWorking Directory or '.' is :

import(
  "os" 
  "fmt"
  "log"
)

func main() {
  dir, err := os.Getwd()
    if err != nil {
        log.Fatal(err)
    }
  fmt.Println(dir)
}

the os.Getwd() function will return the current working directory.

ben
  • 740
  • 7
  • 16
  • 7
    This is not correct. This returns the working directory of the user executing the process and not the directory of the file. Use filepath.abs. – PodTech.io Mar 01 '20 at 19:50
  • 1
    it returns the working Directory of the running executable file. then if you are using an IDE like goland and there is no config for working directory in the build options then it will run from /tmp , then what usage /tmp have for you!??but if you use os.Getwd() it returns the .exe or elf executable file path. not /tmp. – ben Mar 02 '20 at 12:30
  • @Bit Using base template of debugging in such an IDE, yes give you that, then just hit 'Edit Configuration' and fill 'Output Directory', so you will see 'os.Args[0]' path is what you want – Mamrezo Jun 01 '20 at 14:29
12

os.Executable: https://tip.golang.org/pkg/os/#Executable

filepath.EvalSymlinks: https://golang.org/pkg/path/filepath/#EvalSymlinks

Full Demo:

package main

import (
    "fmt"
    "os"
    "path/filepath"
)

func main() {
    var dirAbsPath string
    ex, err := os.Executable()
    if err == nil {
        dirAbsPath = filepath.Dir(ex)
        fmt.Println(dirAbsPath)
        return
    }

    exReal, err := filepath.EvalSymlinks(ex)
    if err != nil {
        panic(err)
    }
    dirAbsPath = filepath.Dir(exReal)
    fmt.Println(dirAbsPath)
}
vikyd
  • 1,807
  • 1
  • 19
  • 28
11
filepath.Abs("./")

Abs returns an absolute representation of path. If the path is not absolute it will be joined with the current working directory to turn it into an absolute path.

As stated in the comment, this returns the directory which is currently active.

Ari Seyhun
  • 11,506
  • 16
  • 62
  • 109
  • 14
    This returns the current directory, not the directory of the current file. For instance, this would be different if the executable was called from a different path. – Fujii Sep 11 '17 at 20:13
7

Do not use the "Answer recommended by Go Language" with runtime.Caller(0).

That works when you go build or go install a program, because you are re-compiling it.

But when you go build a program and then distribute it (copy) on your colleagues' workstations (who don't have Go, and just need the executable), the result of runtime.Caller(0) would still be the path of where you built it (from your computer).
Ie a path which would likely not exist on their own computer.

os.Args[0] or, better, os.Executable() (mentioned here) and kardianos/osext (mentioned here and here), are more reliable.

VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
  • 1
    Likewise any answer that uses getwd will also be wrong especially when the exe is placed in the path and executed from another location. – hookenz Jul 01 '22 at 10:32
5

If you use package osext by kardianos and you need to test locally, like Derek Dowling commented:

This works fine until you'd like to use it with go run main.go for local development. Not sure how best to get around that without building an executable beforehand each time.

The solution to this is to make a gorun.exe utility instead of using go run. The gorun.exe utility would compile the project using "go build", then run it right after, in the normal directory of your project.

I had this issue with other compilers and found myself making these utilities since they are not shipped with the compiler... it is especially arcane with tools like C where you have to compile and link and then run it (too much work).

If anyone likes my idea of gorun.exe (or elf) I will likely upload it to github soon..

Sorry, this answer is meant as a comment, but I cannot comment due to me not having a reputation big enough yet.

Alternatively, "go run" could be modified (if it does not have this feature already) to have a parameter such as "go run -notemp" to not run the program in a temporary directory (or something similar). But I would prefer just typing out gorun or "gor" as it is shorter than a convoluted parameter. Gorun.exe or gor.exe would need to be installed in the same directory as your go compiler

Implementing gorun.exe (or gor.exe) would be trivial, as I have done it with other compilers in only a few lines of code... (famous last words ;-)

Another Prog
  • 841
  • 13
  • 19
  • 8
    If you want it to both work with "go run" and built executable then simply use `_, callerFile, _, _ := runtime.Caller(0)` `executablePath := filepath.Dir(callerFile)` instead – Jocelyn Jul 24 '17 at 09:16
  • @Jocelyn, your comment is so great that you should make that into a full answer! This certainly did the trick for me — on my own setup, I have a local copy of the environment in macOS, which I mostly use to catch syntax errors (and a few semantic ones); then I sync the code to the deployment server, which runs under Ubuntu Linux, and of course the environment is completely different... so there is a real need to figure out where the file paths are to properly load templates, configuration files, static files, etc... – Gwyneth Llewelyn Jun 10 '20 at 11:56
5

Sometimes this is enough, the first argument will always be the file path

package main

import (
    "fmt"
    "os"
)


func main() {
    fmt.Println(os.Args[0])

    // or
    dir, _ := os.Getwd()
    fmt.Println(dir)
}
Isaac Weingarten
  • 977
  • 10
  • 15
5
dir, err := os.Getwd()
    if err != nil {
        fmt.Println(err)
    }

this is for golang version: go version go1.13.7 linux/amd64

works for me, for go run main.go. If I run go build -o fileName, and put the final executable in some other folder, then that path is given while running the executable.

gaurav arora
  • 195
  • 3
  • 11
0

None of the answers here worked for me, at least on go version go1.16.2 darwin/amd64. This is the only thing close to the __dirname functionality in node

This was posted by goland engineer Daniil Maslov in the jetbrains forums

pasted below for easier reading:


The trick is actually very simple and is to get the current executing and add .. to the project root.

Create a new directory and file like testing_init.go with the following content:

package testing_init

import (
  "os"
  "path"
  "runtime"
)

func init() {
  _, filename, _, _ := runtime.Caller(0)
  dir := path.Join(path.Dir(filename), "..")
  err := os.Chdir(dir)
  if err != nil {
    panic(err)
  }
}

After that, just import the package into any of the test files:


package main_test

import (
  _ "project/testing_init"
)

Now you can specify paths from the project root

1mike12
  • 2,946
  • 3
  • 27
  • 36
0

I get the information from the log package (if you also need the linenumber where its called)

log.Lshortfile
Zwen2012
  • 3,360
  • 9
  • 40
  • 67
0

The following method checks if you might be using go run . on your local machine, and if so, it skips changing the directory. In practice, this may be good enough for your use case. I should note that if you cd into a subdirectory and run go mod .., your working directory will differ.

The following presumes that you're running Linux. Other OSes may require different path comparisons.

package main

import (
    "os"
    "fmt"
    "regexp"
    "path/filepath"
)

func main() {

    // /tmp/ is an os-specific dir holding executables compiled by `go run`
    matched, err := regexp.MatchString("^/tmp/", os.Args[0])

    if err != nil {
        fmt.Println(err.Error())
        os.Exit(1)
    }

    if !matched {
        // if we're in this block, we're running a pre-compiled binary
        newDir := filepath.Dir(os.Args[0])

        fmt.Printf("changing dir to: %s\n", newDir)
        os.Chdir(newDir)

    } else {
        // we're running with something like `go run .`
        fmt.Println("not changing dir")
    }
}
andrew-e
  • 724
  • 7
  • 10
0

you can use this code to get the executable directory:

package main

import (
    "fmt"
    "os"
    "path/filepath"
)

func main() {
    exePath, err := os.Executable() // Get the executable file's path
    if err != nil {
        fmt.Println("Error:", err)
        return
    }

    dirPath := filepath.Dir(exePath) // Get the directory of the executable file

    fmt.Println("executable directory:", dirPath)
}
Md Kamruzzaman
  • 346
  • 1
  • 8
-1
// GetCurrentDir
func GetCurrentDir() string {
    p, _ := os.Getwd()
    return p
}
// GetParentDir
func GetParentDir(dirctory string) string {
    return substr(dirctory, 0, strings.LastIndex(dirctory, "/"))
}
func substr(s string, pos, length int) string {
    runes := []rune(s)
    l := pos + length
    if l > len(runes) {
        l = len(runes)
    }
    return string(runes[pos:l])
}
zld126126
  • 37
  • 2
  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Oct 09 '21 at 05:26
-1

If your file is not in the main package then the above answers won't work I tried different approaches to find find the directory of the currently running file but failed.

The best possible answer is in the question itself this is how I find the current working directory of the file which is not in the main package.

_, filename, _, _ := runtime.Caller(1)
pwd := path.Dir(filename)
Zubair Hassan
  • 776
  • 6
  • 14
-5

Gustavo Niemeyer's answer is great. But in Windows, runtime proc is mostly in another dir, like this:

"C:\Users\XXX\AppData\Local\Temp"

If you use relative file path, like "/config/api.yaml", this will use your project path where your code exists.