Uzyskaj katalog domowy użytkownika

94

Czy poniższy sposób jest najlepszym sposobem uzyskania katalogu domowego uruchomionego użytkownika? A może jest jakaś konkretna funkcja, którą przejrzałem?

os.Getenv("HOME")

Jeśli powyższe jest poprawne, to czy ktoś wie, czy takie podejście gwarantuje działanie na platformach innych niż Linux, np. Windows?

Paul Ruane
źródło
2
$HOMENie jest koniecznie katalog domowy użytkownika. Na przykład mogę pisać export HOME=/something/elseprzed uruchomieniem programu. Zwykle oznacza to, że chcę, aby program z /something/elsejakiegoś powodu traktował jako mój katalog domowy i zwykle program powinien to zaakceptować. Ale jeśli naprawdę potrzebujesz użytkownika rzeczywisty katalog domowy, zmienna środowiskowa nie musi ci go.
Keith Thompson
1
@KeithThompson Dzięki, ale dla moich celów jest wystarczająco dobre.
Paul Ruane

Odpowiedzi:

176

W go 1.0.3 (prawdopodobnie również wcześniej) działa:

package main
import (
    "os/user"
    "fmt"
    "log"
)
func main() {
    usr, err := user.Current()
    if err != nil {
        log.Fatal( err )
    }
    fmt.Println( usr.HomeDir )
}

Jeśli ważne jest cross-kompilacji, należy rozważyć z homedirbiblioteki

Vlad Didenko
źródło
1
Super, wielkie dzięki. Nie był świadomy tej zmiany. To jest dokładnie to, czego szukałem.
Paul Ruane
Czy to tylko ja, czy jestem jedyną osobą, w której robienie tego w systemie Windows zajmuje kilka sekund?
Htbaa
Zdecydowanie wydaje się to natychmiastowe na mojej 64-bitowej maszynie wirtualnej Windows 7.
Vlad Didenko
4
Należy pamiętać, że od wersji 1.1, "usr, err: = user.Current ()" wyświetli na osx błąd "user: Current not zaimplementowany w darwin / amd64".
Oleiade,
11
nie działa, gdy skompilowano krzyżowo code.google.com/p/go/issues/detail?id=6376
Wisznu
61

os.UserHomeDir ()

W go1.12 + możesz użyć os.UserHomeDir ()

home, err := os.UserHomeDir()

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

To powinno działać nawet bez włączonego CGO (tj. FROM scratch) I bez konieczności analizowania /etc/passwdlub innych takich bzdur.

coolaj86
źródło
23

Na przykład,

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
źródło
1
To jest to samo podejście, co Jeremy W. Sherman, które wydaje się być obecnie jedynym sposobem. Wielkie dzięki.
Paul Ruane
2
To jest podejście zastosowane w viper util.go userHomeDir ()
RubenLaguna
W prawie wszystkich przypadkach, w których widzę to używane, NIE jest to właściwe. USERPROFILEto katalog główny przestrzeni dyskowej użytkownika w systemie, ale NIE jest to miejsce, w którym aplikacje powinny zapisywać dane poza oknem dialogowym zapisywania. Jeśli masz konfigurację aplikacji, powinna być zapisana, APPDATAa jeśli masz pamięć podręczną aplikacji (lub duże pliki, które nie powinny być synchronizowane przez sieć), powinna zostać zapisana LOCALAPPDATAw systemie Windows.
Micah Zoltu
4

Oto ładny, zwięzły sposób na zrobienie tego (jeśli używasz tylko systemu opartego na UNIX):

import (
  "os"
)

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

To tylko odpytuje zmienną środowiskową $ HOME.

--- Edytować ---

Teraz widzę, że ta sama metoda została zasugerowana powyżej. Zostawię ten przykład jako roztwór destylowany.

Murphy Randle
źródło
2
1. to sugerowano wcześniej, 2. nie jest to platforma wieloplatformowa, 3. zaakceptowana odpowiedź już rozwiązuje ten problem w lepszy sposób.
Paul Ruane
3

Podobna odpowiedź do @peterSO, ale szanuje XDG_CONFIG_HOMEścieżkę dla Linuksa.

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
źródło
Chciałbym, aby ta odpowiedź została zaktualizowana, aby szanować również system Windows! APPDATAdo konfiguracji i LOCALAPPDATAdużych plików. Dla ogólnego przeznaczenia polecam, LOCALAPPDATAaby twórcy aplikacji domyślnie nie niszczyli sieci korporacyjnych. 😊
Micah Zoltu
2

Powinieneś użyć zmiennej środowiskowej USERPROFILElub HOMEPATHw systemie Windows. Zobacz Rozpoznane zmienne środowiskowe (mile widziany byłby link do bardziej odpowiedniej dokumentacji).

Jeremy W. Sherman
źródło
Dzięki. Czy chcesz powiedzieć, że HOME nie jest zapełniane przez Go dla każdej platformy (która deleguje bezpośrednio do zmiennych środowiska O / S) i muszę sprawdzić odpowiednią zmienną każdej platformy, aby zidentyfikować katalog domowy?
Paul Ruane
Przyjrzałem się źródłu i wygląda na to, że HOME nie jest automatycznie wypełniane. Wygląda na to, że nie ma (obecnie) narzędzia niezależnego od platformy do uzyskiwania katalogu domowego.
Paul Ruane
@PaulRuane Ponieważ platformy używają różnych zmiennych, po prostu zignoruj ​​system operacyjny, sprawdź obie zmienne i wybierz tę, która jest zapełniona. Jeśli oba są zdefiniowane, użyłbym HOME, ponieważ prawdopodobnie oznacza to, że biegasz pod cygwin.
Jeremy W. Sherman
W większości przypadków NIE powinieneś używać USERPROFILEani HOMEPATHw systemie Windows. W prawie wszystkich przypadkach, w których deweloperzy ich używają, powinni używać APPDATAlub LOCALAPPDATA(w zależności od tego, czy rozsądna jest synchronizacja zawartości przez sieć podczas logowania / wylogowywania).
Micah Zoltu
2

go1.8rc2 ma funkcję go / build / defaultGOPATH, która pobiera katalog domowy. https://github.com/golang/go/blob/go1.8rc2/src/go/build/build.go#L260-L277

Poniższy kod jest wyodrębniany z funkcji defaultGOPATH.

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
źródło
O ile realizacja tej funkcji Go jest interesująca, jest to gorsze rozwiązanie niż użycie standardowej funkcji bibliotecznej opisanej w zaakceptowanej odpowiedzi. (I jest to to samo podejście, co odpowiedź peterSO sprzed sześciu lat.)
Paul Ruane
W większości przypadków nie jest to właściwe rozwiązanie . Zobacz komentarze do innych odpowiedzi, ale TL; DR jest tym APPDATAlub LOCALAPPDATAprawie zawsze jest właściwym wyborem, a nie USERPROFILEw systemie Windows.
Micah Zoltu