Obtenha o diretório inicial do usuário

90

A melhor maneira de obter o diretório inicial do usuário em execução é a seguinte? Ou há uma função específica que eu olhei?

os.Getenv("HOME")

Se o acima estiver correto, por acaso alguém sabe se esta abordagem funcionará garantidamente em plataformas não Linux, por exemplo, Windows?

Paul Ruane
fonte
2
$HOMEnão é necessariamente o diretório inicial do usuário. Por exemplo, posso escrever export HOME=/something/elseantes de lançar seu programa. Normalmente, isso significa que desejo que o programa seja tratado /something/elsecomo meu diretório inicial por algum motivo e, geralmente, o programa deve aceitar isso. Mas se você realmente precisa do diretório inicial real do usuário , uma variável de ambiente não necessariamente o fornecerá a você.
Keith Thompson
1
@KeithThompson Obrigado, mas para os meus propósitos é bom o suficiente.
Paul Ruane

Respostas:

174

No go 1.0.3 (provavelmente antes também) funciona o seguinte:

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

Se for importante a compilação cruzada, considere a homedirbiblioteca

Vlad Didenko
fonte
1
Incrível, muito obrigado. Não estava ciente dessa mudança. Isso é exatamente o que eu estava procurando.
Paul Ruane,
Sou só eu ou sou o único em que fazer isso no Windows leva vários segundos?
Htbaa
Definitivamente, parece instantâneo na minha VM de 64 bits do Windows 7.
Vlad Didenko,
4
Esteja ciente de que a partir de 1.1, "usr, err: = user.Current ()" gerará um erro "user: Current not Implement on darwin / amd64" no osx.
Oleiade
11
não funciona quando cross-compiled code.google.com/p/go/issues/detail?id=6376
Vishnu
55

os.UserHomeDir ()

Em go1.12 + você pode usar os.UserHomeDir ()

home, err := os.UserHomeDir()

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

Isso deve funcionar mesmo sem o CGO habilitado (ou seja FROM scratch) e sem ter que analisar /etc/passwdou fazer qualquer outra coisa sem sentido.

Coolaj86
fonte
22

Por exemplo,

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
fonte
1
Esta é a mesma abordagem de Jeremy W Sherman, que parece ser a única maneira no momento. Muito Obrigado.
Paul Ruane
2
Esta é a abordagem seguida em viper util.go userHomeDir ()
RubenLaguna 01 de
Em quase todos os casos em que vejo isso sendo usado, NÃO é a coisa certa a se fazer. USERPROFILEé a raiz do espaço de armazenamento do usuário no sistema, mas NÃO é o local onde os aplicativos devem ser gravados fora de um prompt de diálogo de salvamento. Se você tiver a configuração do aplicativo, ela deve ser gravada APPDATAe, se você tiver o cache do aplicativo (ou arquivos grandes que não devem ser sincronizados pela rede), ela deve ser gravada LOCALAPPDATAno Windows.
Micah Zoltu
4

Esta é uma maneira agradável e concisa de fazer isso (se você estiver executando apenas em um sistema baseado em UNIX):

import (
  "os"
)

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

Isso apenas consulta a variável de ambiente $ HOME.

--- Editar ---

Agora vejo que esse mesmo método foi sugerido acima. Vou deixar este exemplo aqui como uma solução destilada.

Murphy Randle
fonte
2
1. já foi sugerido antes, 2. não é multiplataforma, 3. a resposta aceita já resolve esse problema de uma maneira melhor.
Paul Ruane
3

Resposta semelhante a @peterSO, mas respeita o XDG_CONFIG_HOMEcaminho para o 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
fonte
Adoraria ver esta resposta atualizada para respeitar o Windows também! APPDATApara configuração e LOCALAPPDATApara arquivos grandes. Para uma "casa" de uso geral, eu recomendo LOCALAPPDATA, por padrão, os desenvolvedores de aplicativos não estão destruindo redes corporativas. 😊
Micah Zoltu
2

Você deve usar a variável de ambiente USERPROFILEou HOMEPATHno Windows. Consulte Variáveis ​​de ambiente reconhecidas (um link de documentação mais apropriado seria bem-vindo).

Jeremy W. Sherman
fonte
Obrigado. Você está dizendo, então, que o HOME não é preenchido pelo Go para cada plataforma (que delega diretamente nas variáveis ​​de env O / S) e devo verificar a respectiva variável de cada plataforma para identificar o diretório home?
Paul Ruane
Dei uma olhada na fonte e parece que HOME não é preenchida automaticamente. Parece que não há (atualmente) nenhum recurso independente de plataforma para obter o diretório inicial.
Paul Ruane
@PaulRuane Como as plataformas usam variáveis ​​diferentes, simplesmente ignore o SO, verifique ambas as variáveis ​​e vá com a que estiver preenchida. Se ambos estiverem definidos, eu usaria HOME, pois isso provavelmente significa que você está executando no cygwin.
Jeremy W. Sherman,
Você NÃO deve usar USERPROFILEou HOMEPATHno Windows na grande maioria dos casos. Em quase todos os casos em que os desenvolvedores os usam, o que eles deveriam usar é APPDATAou LOCALAPPDATA(dependendo se é razoável que o conteúdo seja sincronizado pela rede no login / logout).
Micah Zoltu
2

go1.8rc2 tem a função go / build / defaultGOPATH que obtém o diretório inicial. https://github.com/golang/go/blob/go1.8rc2/src/go/build/build.go#L260-L277

O código a seguir é extraído da função 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
fonte
Embora a implementação desta função Go seja interessante, esta é uma solução pior do que usar a função de biblioteca padrão descrita na resposta aceita. (E é a mesma abordagem que a resposta de PeterSO de seis anos atrás.)
Paul Ruane
Esta não é a solução certa na maioria dos casos . Veja comentários em outras respostas, mas o TL; DR é essa APPDATAou LOCALAPPDATAquase sempre a escolha certa, não USERPROFILE, no Windows.
Micah Zoltu