Obtener el directorio de inicio del usuario

94

¿Es la siguiente la mejor manera de obtener el directorio de inicio del usuario en ejecución? ¿O hay una función específica que he desarrollado?

os.Getenv("HOME")

Si lo anterior es correcto, ¿alguien sabe si se garantiza que este enfoque funcione en plataformas que no sean Linux, por ejemplo, Windows?

Paul Ruane
fuente
2
$HOMEno es necesariamente el directorio de inicio del usuario. Por ejemplo, puedo escribir export HOME=/something/elseantes de lanzar su programa. Por lo general, eso significa que quiero que el programa lo trate /something/elsecomo mi directorio de inicio por alguna razón, y generalmente el programa debería aceptarlo. Pero si realmente necesita el directorio de inicio real del usuario , una variable de entorno no necesariamente se lo proporcionará.
Keith Thompson
1
@KeithThompson Gracias, pero para mis propósitos es lo suficientemente bueno.
Paul Ruane

Respuestas:

175

En go 1.0.3 (probablemente antes también) funciona lo siguiente:

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

Si es importante realizar una compilación cruzada, considere la homedirbiblioteca

Vlad Didenko
fuente
1
Impresionante, muchas gracias. No estaba al tanto de este cambio. Esto es exactamente lo que estaba buscando.
Paul Ruane
¿Soy solo yo o soy el único en el que hacer esto en Windows lleva varios segundos?
Htbaa
Definitivamente parece instantáneo en mi máquina virtual con Windows 7 de 64 bits.
Vlad Didenko
4
Tenga en cuenta que a partir de la versión 1.1, "usr, err: = user.Current ()" arrojará un error "user: Current no implementado en darwin / amd64" en osx.
Oleiade
11
no funciona cuando se compila en forma cruzada code.google.com/p/go/issues/detail?id=6376
Vishnu
61

os.UserHomeDir ()

En go1.12 + puede usar os.UserHomeDir ()

home, err := os.UserHomeDir()

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

Eso debería funcionar incluso sin CGO habilitado (es decir FROM scratch) y sin tener que analizar /etc/passwdu otras tonterías similares.

coolaj86
fuente
23

Por ejemplo,

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
fuente
1
Este es el mismo enfoque que Jeremy W Sherman, que parece ser el único camino en la actualidad. Muchas gracias.
Paul Ruane
2
Este es el enfoque seguido en viper util.go userHomeDir ()
RubenLaguna
En casi todos los casos en los que veo que se usa, esto NO es lo correcto. USERPROFILEes la raíz del espacio de almacenamiento del usuario en el sistema, pero NO es el lugar donde las aplicaciones deben escribir fuera de un cuadro de diálogo para guardar. Si tiene una configuración de la aplicación, debe escribirse en ella APPDATAy si tiene un caché de la aplicación (o archivos grandes que no deben sincronizarse a través de una red) debe escribirse LOCALAPPDATAen Windows.
Micah Zoltu
4

Aquí hay una forma agradable y concisa de hacerlo (si solo está ejecutando en un sistema basado en UNIX):

import (
  "os"
)

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

Eso solo consulta la variable de entorno $ HOME.

--- Editar ---

Ahora veo que este mismo método se sugirió anteriormente. Dejaré este ejemplo aquí como una solución destilada.

Murphy Randle
fuente
2
1. se ha sugerido antes, 2. no es multiplataforma, 3. la respuesta aceptada ya resuelve este problema de una mejor manera.
Paul Ruane
3

Respuesta similar a @peterSO pero respeta la XDG_CONFIG_HOMEruta para 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
fuente
¡Me encantaría ver esta respuesta actualizada para respetar Windows también! APPDATApara configuración y LOCALAPPDATApara archivos grandes. Para un "hogar" de propósito general, recomiendo LOCALAPPDATAque, por defecto, los desarrolladores de aplicaciones no destruyan las redes corporativas. 😊
Micah Zoltu
2

Debe utilizar la variable de entorno USERPROFILEo HOMEPATHen Windows. Consulte Variables de entorno reconocidas (se agradecería un enlace de documentación más apropiado).

Jeremy W. Sherman
fuente
Gracias. ¿Está diciendo, entonces, que HOME no está poblado por Go para cada plataforma (que delega directamente en las vars env O / S) y que debo verificar la variable respectiva de cada plataforma para identificar el directorio de inicio?
Paul Ruane
He echado un vistazo a la fuente y parece que HOME no se completa automáticamente. Parece que (actualmente) no existe una función independiente de la plataforma para obtener el directorio de inicio.
Paul Ruane
@PaulRuane Dado que las plataformas usan diferentes variables, simplemente ignore el sistema operativo, verifique ambas variables y elija la que esté poblada. Si ambos están definidos, lo usaría HOME, ya que eso probablemente significa que está ejecutando cygwin.
Jeremy W. Sherman
NO debe usar USERPROFILEo HOMEPATHen Windows en la gran mayoría de los casos. En casi todos los casos en los que los desarrolladores los usan, lo que deberían usar es APPDATAo LOCALAPPDATA(dependiendo de si es razonable que el contenido se sincronice a través de la red al iniciar / cerrar sesión).
Micah Zoltu
2

go1.8rc2 tiene la función go / build / defaultGOPATH que obtiene el directorio de inicio. https://github.com/golang/go/blob/go1.8rc2/src/go/build/build.go#L260-L277

El siguiente código se extrae de la función 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
fuente
Si bien la implementación de esta función Go es interesante, esta es una solución peor que usar la función de biblioteca estándar descrita en la respuesta aceptada. (Y es el mismo enfoque que la respuesta de peterSO de hace seis años.)
Paul Ruane
Esta no es la solución adecuada en la mayoría de los casos . Vea los comentarios sobre otras respuestas, pero el TL; DR es eso APPDATAo LOCALAPPDATAcasi siempre es la opción correcta, no USERPROFILE, en Windows.
Micah Zoltu