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

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или другой подобной ерунды.

coolaj86
источник
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)
}
Питер SO
источник
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)
}
Hnakamur
источник
Хотя реализация этой функции Go интересна, это худшее решение, чем использование стандартной библиотечной функции, описанной в принятом ответе. (И это тот же подход, что и ответ peterSO шесть лет назад.)
Пол
В большинстве случаев это неправильное решение . См. Комментарии к другим ответам, но TL; DR - это APPDATAили LOCALAPPDATAпочти всегда правильный выбор, не USERPROFILEв Windows.
Мика Золту,