Получить домашний каталог пользователя


94

Это лучший способ получить домашний каталог работающего пользователя? Или есть какая-то конкретная функция, которую я переиграл?

os.Getenv("HOME")

Если вышесказанное верно, может ли кто-нибудь знать, будет ли этот подход гарантированно работать на платформах, отличных от Linux, например, Windows?


2
$HOMEне обязательно является домашним каталогом пользователя. Например, я могу написать export HOME=/something/elseперед запуском вашей программы. Обычно это означает, что я хочу, чтобы программа по /something/elseкакой-то причине считалась моим домашним каталогом, и обычно программа должна это принять. Но если вам действительно нужен реальный домашний каталог пользователя, переменная среды не обязательно даст вам его.
Кейт Томпсон,

1
@KeithThompson Спасибо, но для моих целей этого достаточно.
Пол Руан

Ответы:


175

В go 1.0.3 (возможно, и раньше) работает следующее:

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

Если это важно для кросс-компиляции, рассмотрим в homedirбиблиотеку


1
Отлично, большое спасибо. Не знал об этом изменении. Это именно то, что я искал.
Paul Ruane

Это только я или я единственный, у кого это в Windows занимает несколько секунд?
Htbaa

Это определенно кажется мгновенным на моей 64-битной виртуальной машине с Windows 7.
Влад Диденко

4
Имейте в виду, что начиная с версии 1.1, «usr, err: = user.Current ()» будет выдавать ошибку «user: Current не реализовано на darwin / amd64» на osx.
Oleiade

11
не работает при кросс-компиляции code.google.com/p/go/issues/detail?id=6376
Вишну

61

os.UserHomeDir ()

В go1.12 + вы можете использовать os.UserHomeDir ()

home, err := os.UserHomeDir()

См. Https://golang.org/pkg/os/#UserHomeDir

Это должно работать даже без включенного CGO (т.е. FROM scratch) и без необходимости синтаксического анализа /etc/passwdили другой подобной ерунды.


23

Например,

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
Это тот же подход, что и у Джереми Шермана, который в настоящее время кажется единственным способом. Большое спасибо.
Пол Руан

2
Это подход, использованный в viper util.go userHomeDir ()
RubenLaguna 01

Почти во всех случаях, когда я вижу, что это используется, это НЕ правильно. USERPROFILE- это корень дискового пространства пользователя в системе, но это НЕ то место, куда приложения должны выполнять запись вне диалогового окна сохранения. Если у вас есть конфигурация приложения, она должна быть записана, APPDATAа если у вас есть кеш приложения (или большие файлы, которые не должны синхронизироваться по сети), он должен быть записан в LOCALAPPDATAWindows.
Мика Золту,

4

Вот хороший и лаконичный способ сделать это (если вы работаете только в системе на основе UNIX):

import (
  "os"
)

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

Это просто запрашивает переменную среды $ HOME.

--- Редактировать ---

Теперь я вижу, что тот же метод был предложен выше. Я оставлю этот пример здесь как дистиллированный раствор.


2
1. это предлагалось ранее, 2. это не кроссплатформенность, 3. принятый ответ уже решает эту проблему лучше.
Пол Руан,

3

Аналогичный ответ на @peterSO, но уважает XDG_CONFIG_HOMEпуть для 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())
}

Хотелось бы, чтобы этот ответ был обновлен, чтобы уважать Windows! APPDATAдля настройки и LOCALAPPDATAдля больших файлов. Для «дома» общего назначения я рекомендую, LOCALAPPDATAчтобы разработчики приложений по умолчанию не разрушали корпоративные сети. 😊
Мика Золту

2

Вы должны использовать переменную окружения USERPROFILEили HOMEPATHпод Windows. См. Распознанные переменные среды (приветствуется более подходящая ссылка на документацию).


Спасибо. Значит, вы говорите, что HOME не заполняется Go для каждой платформы (который он делегирует непосредственно переменным окружения O / S), и я должен проверить соответствующую переменную каждой платформы, чтобы определить домашний каталог?
Paul Ruane

Я посмотрел на источник, и оказалось, что HOME не заполняется автоматически. Кажется, что (в настоящее время) нет независимой от платформы средства для получения домашнего каталога.
Paul Ruane

@PaulRuane Поскольку платформы используют разные переменные, просто игнорируйте ОС, проверьте обе переменные и выберите ту, что заполнена. Если оба определены, я бы использовал HOME, поскольку это, вероятно, означает, что вы работаете под cygwin.
Джереми В. Шерман

Вы НЕ должны использовать USERPROFILEили HOMEPATHв Windows в подавляющем большинстве случаев. Почти во всех случаях, когда разработчики используют их, они должны использовать APPDATAили LOCALAPPDATA(в зависимости от того, разумно ли синхронизировать содержимое по сети при входе в систему / выходе из системы).
Мика Золту,

2

go1.8rc2 имеет функцию go / build / defaultGOPATH, которая получает домашний каталог. https://github.com/golang/go/blob/go1.8rc2/src/go/build/build.go#L260-L277

Следующий код извлечен из функции 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)
}

Хотя реализация этой функции Go интересна, это худшее решение, чем использование стандартной библиотечной функции, описанной в принятом ответе. (И это тот же подход, что и ответ peterSO шесть лет назад.)
Пол

В большинстве случаев это неправильное решение . См. Комментарии к другим ответам, но TL; DR - это APPDATAили LOCALAPPDATAпочти всегда правильный выбор, не USERPROFILEв Windows.
Мика Золту,
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.