99

Is the following the best way of obtaining the running user's home directory? Or is there a specific function that I've ovelooked?

os.Getenv("HOME")

If the above is correct, does anyone happen to know whether this approach is guaranteed to work on non-Linux platforms, e.g. Windows?

lospejos
  • 1,888
  • 3
  • 17
  • 31
Paul Ruane
  • 34,423
  • 11
  • 60
  • 77
  • 2
    `$HOME` is not *necessarily* the user's home directory. For example, I can write `export HOME=/something/else` before launching your program. Usually that means I *want* the program to treat `/something/else` as my home directory for some reason, and usually the program should accept that. But if you really need the user's *actual* home directory, an environment variable won't necessarily give it to you. – Keith Thompson Oct 27 '11 at 23:48

7 Answers7

188

Since go 1.12 the recommended way is:

package main
import (
    "os"
    "fmt"
    "log"
)
func main() {
    dirname, err := os.UserHomeDir()
    if err != nil {
        log.Fatal( err )
    }
    fmt.Println( dirname )
}

Old recommendation:

In go 1.0.3 ( probably earlier, too ) the following works:

package main
import (
    "os/user"
    "fmt"
    "log"
)
func main() {
    usr, err := user.Current()
    if err != nil {
        log.Fatal( err )
    }
    fmt.Println( usr.HomeDir )
}
coolaj86
  • 64,368
  • 14
  • 90
  • 108
Vlad Didenko
  • 3,613
  • 4
  • 22
  • 34
  • Is it just me or am I the only one where doing this on Windows takes several seconds? – Htbaa Apr 17 '13 at 09:12
  • It definitely seems instant on my Windows 7 64bit VM. – Vlad Didenko Apr 22 '13 at 01:29
  • 4
    Be aware that as of go 1.1, "usr, err := user.Current()" will throw a "user: Current not implemented on darwin/amd64" error on osx. – Oleiade Jul 27 '13 at 09:36
  • It works on Mac OS 10.6.8 using Go versions as old as 1.0.3, 32- and 64-bit. – George Mar 10 '14 at 22:00
  • 11
    doesn't work when cross compiled https://code.google.com/p/go/issues/detail?id=6376 – Vishnu Aug 13 '14 at 09:10
  • Does not work in static builds because a error related with libc: https://sourceware.org/bugzilla/show_bug.cgi?id=20468 – ton Apr 15 '19 at 14:26
  • 1
    Please DO NOT USE THIS, use ```os.UserHomeDir()``` instead, as it takes into consideration a user's environment variables and the XDG Base Directory Specification! See the answer below for details. – ZacWolf Mar 16 '21 at 19:27
  • Answer doesn't compile on GO 1.13.8 Darwin64bit. @ZacWolf's answer works, `os.UserHomeDir()` – William Apr 08 '21 at 15:36
76

os.UserHomeDir()

In go1.12+ you can use os.UserHomeDir()

home, err := os.UserHomeDir()

See https://golang.org/pkg/os/#UserHomeDir

That should work even without CGO enabled (i.e. FROM scratch) and without having to parse /etc/passwd or other such nonsense.

coolaj86
  • 64,368
  • 14
  • 90
  • 108
  • 1
    I hope enough people read-down this list because THIS is the function that should be used, as it takes into consideration a user's environment variables and the XDG Base Directory Specification! – ZacWolf Mar 16 '21 at 19:25
  • This would even better if you use os.UserCacheDir() and os.UserConfigDir(); particularly for people with home directories on the likes of NFS or using roaming profiles etc. – Cameron Kerr Apr 09 '21 at 04:07
23

For example,

package main

import (
    "fmt"
    "os"
    "runtime"
)

func UserHomeDir() string {
    if runtime.GOOS == "windows" {
        home := os.Getenv("HOMEDRIVE") + os.Getenv("HOMEPATH")
        if home == "" {
            home = os.Getenv("USERPROFILE")
        }
        return home
    }
    return os.Getenv("HOME")
}

func main() {
    dir := UserHomeDir()
    fmt.Println(dir)
}
peterSO
  • 134,261
  • 26
  • 231
  • 232
  • 1
    This is same approach as Jeremy W Sherman which appears to be the only way at present. Many thanks. – Paul Ruane Oct 28 '11 at 11:22
  • 2
    This is the approach followed in viper util.go [userHomeDir()](https://github.com/spf13/viper/blob/80ab6657f9ec7e5761f6603320d3d58dfe6970f6/util.go#L144-L153) – RubenLaguna Jun 01 '17 at 15:41
  • 1
    In almost all cases where I see this used, this is *NOT* the right thing to do. `USERPROFILE` is the root of the User's storage space on the system, but it is *NOT* the place where applications should be writing to outside of a save dialog prompt. If you have application config, it should be written to `APPDATA` and if you have application cache (or large files that shouldn't sync over a network) it should be written to `LOCALAPPDATA` on Windows. – Micah Zoltu Apr 22 '20 at 08:13
4

Here's a nice, concise way to do it (if you're only running on a UNIX based system):

import (
  "os"
)

var home string = os.Getenv("HOME")

That just queries the $HOME environment variable.

--- Edit ---

I now see that this same method was suggested above. I'll leave this example here as a distilled solution.

Murphy Randle
  • 748
  • 8
  • 18
  • 2
    1. it's been suggested before, 2. it's not cross-platform, 3. the accepted answer already solves this problem in a better way. – Paul Ruane Oct 04 '13 at 11:35
4

Similar answer to @peterSO but respects the XDG_CONFIG_HOME path for linux.

package main

import (
    "fmt"
    "os"
    "runtime"
)

func userHomeDir() string {
    if runtime.GOOS == "windows" {
        home := os.Getenv("HOMEDRIVE") + os.Getenv("HOMEPATH")
        if home == "" {
            home = os.Getenv("USERPROFILE")
        }
        return home
    } else if runtime.GOOS == "linux" {
        home := os.Getenv("XDG_CONFIG_HOME")
        if home != "" {
            return home
        }
    }
    return os.Getenv("HOME")
}

func main() {
    fmt.Println(userHomeDir())
}
Miguel Mota
  • 17,966
  • 5
  • 37
  • 55
  • Would love to see this answer updated to respect Windows too! `APPDATA` for configuration and `LOCALAPPDATA` for large files. For a general purpose "home" I recommend `LOCALAPPDATA` so by default application developers aren't wrecking corporate networks. – Micah Zoltu Apr 22 '20 at 08:14
2

go1.8rc2 has the go/build/defaultGOPATH function which gets the home directory. https://github.com/golang/go/blob/go1.8rc2/src/go/build/build.go#L260-L277

The following code is extracted from the defaultGOPATH function.

package main

import (
    "fmt"
    "os"
    "runtime"
)

func UserHomeDir() string {
    env := "HOME"
    if runtime.GOOS == "windows" {
        env = "USERPROFILE"
    } else if runtime.GOOS == "plan9" {
        env = "home"
    }
    return os.Getenv(env)
}

func main() {
    dir := UserHomeDir()
    fmt.Println(dir)
}
hnakamur
  • 491
  • 4
  • 14
  • Whilst the implementation of this Go function is interesting, this is a worse solution than using the standard library function described in the accepted answer. (And is the same approach as peterSO's answer from six years ago.) – Paul Ruane Jan 23 '17 at 12:14
  • This is not the right solution in *most cases*. See comments on other answers, but the TL;DR is that `APPDATA` or `LOCALAPPDATA` is almost always the right choice, not `USERPROFILE`, on Windows. – Micah Zoltu Apr 22 '20 at 08:15
2

You should use the environment variable USERPROFILE or HOMEPATH under Windows. See Recognized Environment Variables (a more apropos documentation link would be welcomed).

Jeremy W. Sherman
  • 34,925
  • 5
  • 73
  • 108
  • Thanks. Are you saying, then, that HOME is not populated by Go for each platform (that it delegates directly into the O/S env vars) and I must check each platform's respective variable to identify the home directory? – Paul Ruane Oct 27 '11 at 21:14
  • I've had a look at the source and it appears HOME is not automatically populated. Seems there is (currently) no platform agnostic facility for obtaining the home directory. – Paul Ruane Oct 27 '11 at 21:22
  • @PaulRuane Since the platforms use different variables, just ignore the OS, check both variables, and go with whichever is populated. If both are defined, I would use `HOME`, since that probably means you're running under cygwin. – Jeremy W. Sherman Oct 28 '11 at 04:40
  • 1
    You should *NOT* use `USERPROFILE` or `HOMEPATH` on Windows in the vast majority of cases. In almost all cases where devs use those, what they *should* be using is `APPDATA` or `LOCALAPPDATA` (depending on whether it is reasonable for the contents to sync over the network on login/logout). – Micah Zoltu Apr 22 '20 at 08:12
  • Use ```os.UserHomeDir()``` instead, as it takes into consideration a user's environment variables and the XDG Base Directory Specification! See the answer below for details. – ZacWolf Mar 16 '21 at 19:28