Golang: Операционная система и ввод-вывод
Функции ОС для повседневного использования
При работе над любой программой Go нам понадобятся некоторые функции ОС для работы с системной средой. В этой статье давайте рассмотрим некоторые из основных функций, предоставляемых пакетом os
.
Встроенный os
пакет, предоставляемый Go, дает нам возможность доступа к встроенным функциям операционной системы независимо от платформы. К ним относятся создание процессов, изменение прав пользователей, файловый ввод-вывод и многое другое.
В этом руководстве мы рассмотрим некоторые основные функции, экспортированные из этого пакета, которые помогут нам в повседневных случаях использования.
Глобальные константы и переменные
Пакет os
экспортирует некоторые общие переменные и постоянные значения.
os.PathSeparator
Константа os.PathSeparator
возвращает значение ASCII int
разделителя пути. в Unix-подобных системах разделителем путей является /
, а в случае Windows - \
. Вы можете найти список разделителей путей отсюда.
Поскольку os.PathSeparator
возвращает значение int
, нам нужно преобразовать его в символ с помощью команды форматирования %c
. Приведенная выше программа дает такой результат.
🌶 go run go-os.go os.PathSeparator => 47 os.PathSeparator => /
os.DevNull
константа os.DevNull
возвращает string
, указывающее нулевое устройство операционной системы. Это загадочное виртуальное устройство, которое может потреблять анданные, но нигде не хранится, прямо как черная дыра.
В Unix-подобных системах нулевым устройством по умолчанию является /dev/null
, а в случае Windows - NUL
. Вы можете узнать больше о нулевом устройстве отсюда. В моем случае (macOS) приведенная выше программа дает следующий результат.
🌶 go run go-os.go os.DevNull => /dev/null
os.Args
Переменная os.Args
возвращает slice
строк, представляющих аргументы, переданные команде, запустившей выполнение программы. Мы обсуждали эту переменную в нашем уроке выполнение команд оболочки.
🌶 go run go-os.go value key=value --flag os.Args => [/var/folders/.../go-os value key=value --flag]
Как видно из приведенного выше результата, первый элемент os.Args
всегда является местоположением двоичного исполняемого файла. Остальные аргументы - это настраиваемые значения, передаваемые команде, поэтому выражение os.Args[1:]
может быть очень удобным для получения всех аргументов командной строки.
💡 При создании приложения CLI переменная
os.Args
может быть очень полезной для получения аргументов командной строки пользователя, как мы видели выше.
os.Stdin / os.Stdout / os.Stderr
os.Stdin
, os.Stdout
и os.Stderr
- это открытые файлы в памяти, которые указывают на стандартные потоки ввода-вывода операционной системы. Например, os.Stdin
может читать со стандартного устройства ввода, такого как клавиатура, а os.Stdout
может писать на стандартное устройство вывода, такое как терминальная консоль.
Мы обсудили варианты использования этих потоков в уроке « выполнение команд оболочки ». Вы можете узнать больше о стандартных потоках в этой статье в Википедии.
Выход из процесса с помощью os.Exit
Функция os.Exit(code int)
завершает текущий процесс и выходит из программы с code
целочисленным кодом состояния. Код состояния0
указывает, что процесс был завершен успешно, а код состояния 1
указывает, что процесс завершился с общей ошибкой. Другие коды состояния могут иметь различное значение в зависимости от системы. Вы можете следить за этой поступью, чтобы узнать больше.
Мы можем вызывать os.Exit()
где угодно. Этот вызов принудительно завершит процесс, но никакие отложенные функции не будут выполнены.
В приведенной выше программе мы откладываем выполнение функции, которая выводит «main completed!» при выходе из метода main
. Затем мы задерживаем выполнение функции на 2 секунды, которая существует в процессе с кодом состояния 1
. Затем основная горутина переходит в спящий режим на 3 секунды.
Поскольку вызов time.AfterFunc
выполняет функцию через 2 секунды в своей собственной горутине, процесс немедленно завершается, а отложенная функция никогда не вызывается. Эта программа дает следующий результат.
🌶 go run go-os.go main() started! exit status 1
💡 Мы также можем использовать функцию
Os.Getpid
для получения идентификатора процесса (pid) текущей запущенной программы. Затем мы можем использоватьos.FindProcess
функцию, чтобы вернутьProcess
с заданнымиpid
иProcess.Kill()
методами, чтобы убить процесс.
Обработка переменных среды
Переменные среды могут быть очень полезны для получения информации о среде и условного выполнения некоторых операций на основе их значений. Переменная среды - это пара ключ-значение из string
значений.
Обычно ключ переменной среды (name) представляет собой строку в верхнем регистре, например GOROOT
или GOPATH
. Вы могли использовать такую команду.
GOOS=linux GOARCH=amd64 go build <package-path>
Приведенная выше команда создает двоичный исполняемый файл, зависящий от платформы, для linux/amd64
систем. Здесь GOOS
- это переменная среды со значением amd64
. Однако этот способ указания переменных среды работает только в Unix-подобных системах, а в случае Windows нам нужно использовать команду SET
.
Go предоставляет некоторые базовые функции для чтения и записи переменных среды, не беспокоясь о базовой реализации ОС. Давайте посмотрим на эти общие функции.
os.Environ
Функция os.Environ()
возвращает slice
строк, содержащих пары "ключ-значение" переменных среды текущего запущенного процесса.
В приведенной выше программе мы просто сохраняем все переменные среды в env
и перебираем его с помощью цикла for-range
. Поскольку переменная среды представлена в форме name=value
, мы можем извлечь name
и value
по отдельности, разделив ее символом =
с помощью функции strings.Split
.
🌶 go run go-os.go [0] USER => Uday.Hiwarale [1] PATH => /Users/Uday.Hiwarale/.... [2] LOGNAME => Uday.Hiwarale [4] HOME => /Users/Uday.Hiwarale [5] GOPATH => /Users/Uday.Hiwarale/.... ...
os.Getenv и os.LookupEnv
Если вы хотите прочитать переменную среды, вы можете использовать функцию os.Getenv()
, которая возвращает значение переменной среды. Если переменная пуста или не существует, она вернет пустой string
.
func Getenv(key string) string
С другой стороны, функция os.LookupEnv()
возвращает два значения. Первое значение - это значение переменной окружения, как и функция Getenv
. Второе значение - это boolean
значение, которое будет false
, если переменная среды не существует.
func LookupEnv(key string) (string, bool)
Мы собираемся запустить эту программу с некоторыми переменными окружения. Поскольку функция os.LookupEnv()
дает нам возможность проверить, существует ли переменная среды или нет, мы можем выполнять некоторые условные операции, которые невозможны в случае функции os.Getenv()
.
🌶 FRUIT=mango CAR= go run go-os.go os.Getenv("FRUIT") => mango os.Getenv("CAR") => os.Getenv("COUNTRY") => os.LookupEnv("FRUIT") => mango (exists: true) os.LookupEnv("CAR") => (exists: true) os.LookupEnv("COUNTRY") => (exists: false)
os.Setenv и os.Unsetenv
Функция os.Setenv
устанавливает переменную среды для текущего процесса. Если процесс запускает другой подпроцесс, нам необходимо передать эти переменные среды этому процессу вручную.
func Setenv(key, value string) error
Если при установке переменной среды возникнет ошибка, она вернет error
. Если переменная среды уже существует, ее значение будет переопределено.
Точно так же мы можем удалить переменную среды из текущего процесса, используя функцию Unsetenv
, которая может возвращать ошибку. Если переменная среды, которую мы пытаемся сбросить, не существует, ошибка не возвращается.
func Unsetenv(key string) error
🌶 FRUIT=mango go run go-os.go Setenv(FRUIT) => error(<nil>) Setenv(CAR) => error(<nil>) Env: FRUIT/CAR => banana/audi Unsetenv(FRUIT) => error(<nil>) Unsetenv(COUNTRY) => error(<nil>) Env: FRUIT/CAR => /audi
os.Expand и os.ExpandEnv
Функция os.Expand
заменяет заполнители в строке, указанной выражением $var
или ${var}
, с помощью функции сопоставления. Функция сопоставления считывает заполнитель и возвращает для него значение замены.
func Expand(s string, mapping func(string) string) string
В приведенной выше программе у нас есть строка raw
с некоторыми заполнителями. Мы создали функцию сопоставления mapper
, которая возвращает замещающие значения для этих заполнителей. Теперь мы можем использовать функцию os.Expand
для преобразования этих заполнителей в реальные значения.
🌶 go run go-os.go I am eating mango and driving audi.
Функция os.Expand
может быть очень полезна для обычного текстового редактора, однако функция os.ExpandEnv
очень полезна для обработки необработанной строки с именами переменных среды в качестве заполнителей.
func ExpandEnv(s string) string
Как мы видим, функции ExpandEnv
не требуется функция сопоставления. Эта функция внутренне вызывает функцию os.Expand
с os.Getenv
в качестве функции сопоставления, поэтому значение-заполнитель на самом деле является значением переменной среды в текущем процессе.
🌶 FRUIT=mango CAR=audi go run go-os.go I am eating mango and driving audi in italy.
Получите информацию о системе и пользователях
Иногда нам нужна основная информация о пользователе, который запускает программу, например, имя пользователя и его / ее домашний каталог для доступа или записи некоторых файлов.
os.Hostname
Эта os.Hostname
функция возвращает имя хоста (bash hostname
команда) системы, в которой запущена программа. Эта функция может возвращать error
в случае, если системное имя хоста недоступно из ядра.
func Hostname() (name string, err error)
🌶 go run go-os.go Udays-MBP.local <nil>
os.UserHomeDir
Функция os.UserHomeDir
возвращает домашний каталог текущего пользователя. Домашний каталог - это место, где текущий пользователь, вошедший в систему, может делать абсолютно все. Это похоже на использование переменной среды $HOME
в Unix-подобных системах.
func UserHomeDir() (string, error)
🌶 go run go-os.go /Users/Uday.Hiwarale <nil>
ОС / пользовательский пакет
Чтобы получить дополнительную информацию о текущем вошедшем в систему пользователе, системных пользователях и группах пользователей, нам нужно импортировать os/user
package.
Мы можем использовать функцию user.Current()
, чтобы получить информацию о текущем вошедшем в систему пользователе. Вы также можете использовать user.Lookup(username)
метод, чтобы найти пользователя с определенным именем пользователя. Оба эти метода возвращают структуру User
.
type User struct { Uid string // the user ID Gid string // the primary group ID Username string // the login name Name string // user's real or display name HomeDir string // user's home directory }
🌶 go run go-os.go &user.User{Uid:"502", Gid:"20", Username:"Uday.Hiwarale", Name:"Uday Hiwarale", HomeDir:"/Users/Uday.Hiwarale"} err: <nil>
Рабочие каталоги
В типичной программе, которой требуется доступ к собственной файловой системе, мы работаем либо в текущем рабочем каталоге, где терминал (консоль) запустил программу Go, либо в каталоге, в котором двоичный файл программы находится.
os.Getwd и os.Chdir
В bash мы можем использовать команду pwd
для получения текущего рабочего каталога. Мы также можем использовать команду cd
для изменения рабочего каталога.
В Go пакет os
предоставляет функцию Getwd
для получения текущего рабочего каталога и функцию Chdir
для изменения рабочего каталога.
func Getwd() (dir string, err error) func Chdir(dir string) error
🌶 go run go-os.go [before] cwd: /Users/Uday.Hiwarale/uday-gh/go-os [after] cwd: /Users/Uday.Hiwarale/uday-gh [after] cwd: /Users/Uday.Hiwarale
Как видно из приведенного выше результата, путь к функции Chdir
может быть относительным или абсолютным. Если путь, переданный функции os.Chdir
, является относительным путем, он будет считаться относительно текущего рабочего каталога. Если текущий каталог не может быть установлен на указанный путь, функция Chdir
может вернуть error
.
os. исполняемый
Go - это скомпилированный язык, что означает, что программу можно запустить, только сначала скомпилировав исходный код в двоичный исполняемый файл, а затем запустив этот исполняемый файл. Кроме того, когда мы отправляем программное обеспечение, написанное на Go, мы отправляем двоичные исполняемые файлы, скомпилированные для определенных системных архитектур.
При работе с исходными файлами программы у нас есть привычка использовать относительные пути к файлам в системе. Относительный путь в Go (как ../../file.txt
) разрешен по отношению к текущему рабочему каталогу.
В некоторых случаях нам нужно найти файл относительно самого исполняемого файла Go. Например, если вы передаете клиенту исполняемый файл вместе с файлом file.txt
, и ваша программа зависит от этого файла, то они, вероятно, находятся в одном каталоге.
Поскольку исполняемый файл может быть запущен из любого места в системе, рабочий каталог всегда меняется, и это не может помочь нам найти file.txt
файл. Однако расположение исполняемых файлов всегда постоянно.
Нам нужен путь к исполняемому файлу в самой запущенной программе, чтобы найти file.txt
. Функция os.Executable
возвращает абсолютный путь к запущенному исполняемому файлу в системе.
func Executable() (string, error)
Мы можем использовать пакет path
или path/filepath
для присоединения и разрешения файла в системе относительно текущего исполняемого файла.
Когда указанная выше программа запускается с помощью команды go run
, Go сначала скомпилирует исходный код и создаст двоичный исполняемый файл во временном расположении. Затем он запустит этот исполняемый файл, чтобы получить следующий результат.
🌶 go run go-os.go exeDir /var/folders/jd/mvgp/T/go-build27/b001/exe/go-os
Однако, если мы сами скомпилируем программу в текущем каталоге, мы получим другой результат. На этот раз результат предсказуем.
🌶 go build go-os.go 🌶 ./go-os exeDir /Users/Uday.Hiwarale/uday-gh/go-os/go-os
os.TempDir
Когда программе необходимо подготовить некоторые файлы для предварительной обработки перед их сбросом в конечный каталог, нам необходимо сохранить их в системном каталоге, где пользователь не может их видеть. и система может безопасно собирать их в будущем.
func TempDir() string
Функция os.TempDir
возвращает временный каталог системы. Однако не гарантируется, что в системе всегда есть временный каталог или программа Go будет иметь достаточные разрешения для его использования.
🌶 go run go-os.go tempDir /var/folders/jd/mvgp/T/
💡 Если вы ищете способ создать временный каталог или временный файл, вы можете использовать функции
ioutil.TempDir()
иioutil.TempFile()
.