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?


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


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.


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)
}

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.


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())
}

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).


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)
}

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
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.