Пакет exec
Обзор
Пакет exec запускает внешние команды. Он оборачивает os.StartProcess, чтобы упростить перенаправление стандартного ввода и вывода, подключение ввода-вывода с помощью каналов и выполнение других настроек.
В отличие от системного вызова библиотеки «system» из C и других языков, пакет os/exec преднамеренно не вызывает системную оболочку и не расширяет шаблоны glob или обрабатывает другие расширения, конвейеры или перенаправления, обычно выполняемые оболочками. Пакет ведет себя более похоже на семейство функций «exec» языка C. Для расширения шаблонов glob либо вызовите оболочку напрямую, позаботившись о экранировании потенциально опасных входных данных, либо используйте функцию Glob пакета path/filepath. Для расширения переменных среды используйте пакет os's ExpandEnv.
Обратите внимание, что примеры в этом пакете предполагают систему Unix. Они могут не работать в Windows и не запускаются в Go Playground, используемом golang.org и godoc.org.
Исполняемые файлы в текущем каталоге
Функции Command и LookPath ищут программу в каталогах, указанных в текущем пути, следуя соглашениям операционной системы. Операционные системы в течение десятилетий включали текущий каталог в этот поиск, иногда неявно, а иногда по умолчанию явно настраивали это. Современная практика такова, что включение текущего каталога обычно не ожидается и часто приводит к проблемам безопасности.
Чтобы избежать этих проблем безопасности, начиная с Go 1.19, этот пакет не будет разрешать программу, используя неявный или явный путь, относительный к текущему каталогу. То есть, если вы запустите LookPath («go»), он не вернёт успешно ./go в Unix или .\go.exe в Windows, независимо от того, как настроен путь. Вместо этого, если обычные алгоритмы поиска приведут к такому результату, эти функции возвращают ошибку err, удовлетворяющую errors.Is(err, ErrDot).
Например, рассмотрим следующие фрагменты кода:
path, err := exec.LookPath("prog")
if err != nil {
log.Fatal(err)
}
use(path)
и
cmd := exec.Command("prog")
if err := cmd.Run(); err != nil {
log.Fatal(err)
}
Эти фрагменты кода не найдут и не загрузят ./prog или .\prog.exe, независимо от того, как настроен текущий путь.
Код, который всегда хочет запустить программу из текущего каталога, может быть переписан, чтобы указать "./prog" вместо "prog".
Код, который настаивает на включении результатов из относительных путей, может вместо этого переопределить ошибку, используя проверку errors.Is:
path, err := exec.LookPath("prog")
if errors.Is(err, exec.ErrDot) {
err = nil
}
if err != nil {
log.Fatal(err)
}
use(path)
и
cmd := exec.Command("prog")
if errors.Is(cmd.Err, exec.ErrDot) {
cmd.Err = nil
}
if err := cmd.Run(); err != nil {
log.Fatal(err)
}
Установка переменной среды GODEBUG=execerrdot=0 полностью отключает генерацию ErrDot, временно восстанавливая поведение до Go 1.19 для программ, которые не могут применить более целевые исправления. В будущей версии Go поддержка этой переменной может быть удалена.
Перед добавлением таких переопределений убедитесь, что вы понимаете последствия для безопасности. Подробнее см. https://go.dev/blog/path-security.
Индекс
Примеры
Файлы пакета
exec.go exec_unix.go lp_unix.go
Переменные
ErrDot указывает, что поиск пути разрешил исполняемый файл в текущем каталоге из-за того, что «.’ находится в пути, как неявно, так и явно. Дополнительные сведения см. в документации по пакету.
Обратите внимание, что функции в этом пакете не возвращают ErrDot напрямую. Код должен использовать errors.Is(err, ErrDot), а не err == ErrDot, чтобы проверить, вызвана ли ошибка err этой ситуацией.
var ErrDot = errors.New("cannot run executable found relative to current directory") ErrNotFound — это ошибка, возникающая, если поиск по пути не смог найти исполняемый файл.
var ErrNotFound = errors.New("executable file not found in $PATH") ErrWaitDelay возвращается Cmd.Wait, если процесс завершается с кодом состояния «успех», но его каналы вывода не закрываются до истечения срока ожидания команды WaitDelay.
var ErrWaitDelay = errors.New("exec: WaitDelay expired before I/O complete") func LookPath
func LookPath(file string) (string, error)
LookPath ищет исполняемый файл, имя которого указано в переменной среды PATH. Если file содержит слеш, он проверяется непосредственно, а PATH не рассматривается. В противном случае, при успехе результат — абсолютный путь.
В более ранних версиях Go, LookPath мог возвращать путь, относительный к текущему каталогу. Начиная с Go 1.19, LookPath вместо этого возвращает этот путь вместе с ошибкой, удовлетворяющей errors.Is(err, ErrDot). Дополнительные сведения см. в документации пакета.
Пример
Код:
path, err := exec.LookPath("fortune")
if err != nil {
log.Fatal("installing fortune is in your future")
}
fmt.Printf("fortune is available at %s\n", path)
тип Cmd
Cmd представляет собой внешнюю команду, которая готовится или выполняется.
После вызова методов Cmd.Run, Cmd.Output или Cmd.CombinedOutput объект Cmd нельзя повторно использовать.
type Cmd struct {
// Path is the path of the command to run.
//
// This is the only field that must be set to a non-zero
// value. If Path is relative, it is evaluated relative
// to Dir.
Path string
// Args holds command line arguments, including the command as Args[0].
// If the Args field is empty or nil, Run uses {Path}.
//
// In typical use, both Path and Args are set by calling Command.
Args []string
// Env specifies the environment of the process.
// Each entry is of the form "key=value".
// If Env is nil, the new process uses the current process's
// environment.
// If Env contains duplicate environment keys, only the last
// value in the slice for each duplicate key is used.
// As a special case on Windows, SYSTEMROOT is always added if
// missing and not explicitly set to the empty string.
Env []string
// Dir specifies the working directory of the command.
// If Dir is the empty string, Run runs the command in the
// calling process's current directory.
Dir string
// Stdin specifies the process's standard input.
//
// If Stdin is nil, the process reads from the null device (os.DevNull).
//
// If Stdin is an *os.File, the process's standard input is connected
// directly to that file.
//
// Otherwise, during the execution of the command a separate
// goroutine reads from Stdin and delivers that data to the command
// over a pipe. In this case, Wait does not complete until the goroutine
// stops copying, either because it has reached the end of Stdin
// (EOF or a read error), or because writing to the pipe returned an error,
// or because a nonzero WaitDelay was set and expired.
Stdin io.Reader
// Stdout and Stderr specify the process's standard output and error.
//
// If either is nil, Run connects the corresponding file descriptor
// to the null device (os.DevNull).
//
// If either is an *os.File, the corresponding output from the process
// is connected directly to that file.
//
// Otherwise, during the execution of the command a separate goroutine
// reads from the process over a pipe and delivers that data to the
// corresponding Writer. In this case, Wait does not complete until the
// goroutine reaches EOF or encounters an error or a nonzero WaitDelay
// expires.
//
// If Stdout and Stderr are the same writer, and have a type that can
// be compared with ==, at most one goroutine at a time will call Write.
Stdout io.Writer
Stderr io.Writer
// ExtraFiles specifies additional open files to be inherited by the
// new process. It does not include standard input, standard output, or
// standard error. If non-nil, entry i becomes file descriptor 3+i.
//
// ExtraFiles is not supported on Windows.
ExtraFiles []*os.File
// SysProcAttr holds optional, operating system-specific attributes.
// Run passes it to os.StartProcess as the os.ProcAttr's Sys field.
SysProcAttr *syscall.SysProcAttr
// Process is the underlying process, once started.
Process *os.Process
// ProcessState contains information about an exited process.
// If the process was started successfully, Wait or Run will
// populate its ProcessState when the command completes.
ProcessState *os.ProcessState
Err error // LookPath error, if any; added in Go 1.19
// If Cancel is non-nil, the command must have been created with
// CommandContext and Cancel will be called when the command's
// Context is done. By default, CommandContext sets Cancel to
// call the Kill method on the command's Process.
//
// Typically a custom Cancel will send a signal to the command's
// Process, but it may instead take other actions to initiate cancellation,
// such as closing a stdin or stdout pipe or sending a shutdown request on a
// network socket.
//
// If the command exits with a success status after Cancel is
// called, and Cancel does not return an error equivalent to
// os.ErrProcessDone, then Wait and similar methods will return a non-nil
// error: either an error wrapping the one returned by Cancel,
// or the error from the Context.
// (If the command exits with a non-success status, or Cancel
// returns an error that wraps os.ErrProcessDone, Wait and similar methods
// continue to return the command's usual exit status.)
//
// If Cancel is set to nil, nothing will happen immediately when the command's
// Context is done, but a nonzero WaitDelay will still take effect. That may
// be useful, for example, to work around deadlocks in commands that do not
// support shutdown signals but are expected to always finish quickly.
//
// Cancel will not be called if Start returns a non-nil error.
Cancel func() error // Go 1.20
// If WaitDelay is non-zero, it bounds the time spent waiting on two sources
// of unexpected delay in Wait: a child process that fails to exit after the
// associated Context is canceled, and a child process that exits but leaves
// its I/O pipes unclosed.
//
// The WaitDelay timer starts when either the associated Context is done or a
// call to Wait observes that the child process has exited, whichever occurs
// first. When the delay has elapsed, the command shuts down the child process
// and/or its I/O pipes.
//
// If the child process has failed to exit — perhaps because it ignored or
// failed to receive a shutdown signal from a Cancel function, or because no
// Cancel function was set — then it will be terminated using os.Process.Kill.
//
// Then, if the I/O pipes communicating with the child process are still open,
// those pipes are closed in order to unblock any goroutines currently blocked
// on Read or Write calls.
//
// If pipes are closed due to WaitDelay, no Cancel call has occurred,
// and the command has otherwise exited with a successful status, Wait and
// similar methods will return ErrWaitDelay instead of nil.
//
// If WaitDelay is zero (the default), I/O pipes will be read until EOF,
// which might not occur until orphaned subprocesses of the command have
// also closed their descriptors for the pipes.
WaitDelay time.Duration // Go 1.20
// contains filtered or unexported fields
}
func Command
func Command(name string, arg ...string) *Cmd
Command возвращает структуру Cmd для выполнения указанной программы с заданными аргументами.
Он устанавливает только Path и Args в возвращаемой структуре.
Если name не содержит разделителей пути, Command использует LookPath, чтобы, если это возможно, преобразовать имя в полный путь. В противном случае он использует имя непосредственно как Path.
Поле Args возвращаемого Cmd формируется из имени команды, за которым следуют элементы arg, поэтому arg не должно включать само имя команды. Например, Command("echo", "hello"). Args[0] всегда равно name, а не потенциально разрешённому Path.
В Windows процессы получают всю командную строку как одну строку и выполняют собственное разбиение. Command объединяет и приводит Args к виду командной строки с алгоритмом, совместимым с приложениями, использующими CommandLineToArgvW (что является наиболее распространённым способом). Заметные исключения — msiexec.exe и cmd.exe (и, следовательно, все пакетные файлы), которые имеют другой алгоритм раскрытия. В таких или подобных случаях вы можете самостоятельно выполнить обработку строк и предоставить полную командную строку в SysProcAttr.CmdLine, оставив Args пустым.
Пример
Код:
cmd := exec.Command("tr", "a-z", "A-Z")
cmd.Stdin = strings.NewReader("some input")
var out strings.Builder
cmd.Stdout = &out
err := cmd.Run()
if err != nil {
log.Fatal(err)
}
fmt.Printf("in all caps: %q\n", out.String())
Пример (Среда)
Код:
cmd := exec.Command("prog")
cmd.Env = append(os.Environ(),
"FOO=duplicate_value", // ignored
"FOO=actual_value", // this value is used
)
if err := cmd.Run(); err != nil {
log.Fatal(err)
}
func CommandContext 1.7
func CommandContext(ctx context.Context, name string, arg ...string) *Cmd
CommandContext подобен Command, но включает контекст.
Предоставленный контекст используется для прерывания процесса (вызванного cmd.Cancel или os.Process.Kill), если контекст становится завершенным до того, как команда завершится самостоятельно.
CommandContext устанавливает функцию отмены команды на вызов метода Kill для процесса и оставляет WaitDelay без значения. Вызывающая сторона может изменить поведение отмены, изменив эти поля до запуска команды.
Пример
Код:
ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)
defer cancel()
if err := exec.CommandContext(ctx, "sleep", "5").Run(); err != nil {
// This will fail after 100 milliseconds. The 5 second sleep
// will be interrupted.
}
func (*Cmd) CombinedOutput
func (c *Cmd) CombinedOutput() ([]byte, error)
CombinedOutput выполняет команду и возвращает объединённый стандартный вывод и стандартную ошибку.
Пример
Код:
cmd := exec.Command("sh", "-c", "echo stdout; echo 1>&2 stderr")
stdoutStderr, err := cmd.CombinedOutput()
if err != nil {
log.Fatal(err)
}
fmt.Printf("%s\n", stdoutStderr)
func (*Cmd) Environ 1.19
func (c *Cmd) Environ() []string
Environ возвращает копию среды, в которой будет выполняться команда, в её текущей конфигурации.
Пример
Код:
cmd := exec.Command("pwd")
// Set Dir before calling cmd.Environ so that it will include an
// updated PWD variable (on platforms where that is used).
cmd.Dir = ".."
cmd.Env = append(cmd.Environ(), "POSIXLY_CORRECT=1")
out, err := cmd.Output()
if err != nil {
log.Fatal(err)
}
fmt.Printf("%s\n", out)
func (*Cmd) Output
func (c *Cmd) Output() ([]byte, error)
Output выполняет команду и возвращает её стандартный вывод. Любая возвращённая ошибка обычно будет типа *ExitError. Если c.Stderr было null, Output заполняет [ExitError.Stderr].
Пример
Код:
out, err := exec.Command("date").Output()
if err != nil {
log.Fatal(err)
}
fmt.Printf("The date is %s\n", out)
func (*Cmd) Run
func (c *Cmd) Run() error
Run запускает указанную команду и ждёт её завершения.
Возвращаемая ошибка имеет значение null, если команда выполняется, без проблем копирует stdin, stdout и stderr и завершается с нулевым кодом выхода.
Если команда запускается, но не завершается успешно, ошибка имеет тип *ExitError. Другие типы ошибок могут быть возвращены в других ситуациях.
Если вызывающий горутин имеет заблокированную нить операционной системы с помощью runtime.LockOSThread и изменил любой наследуемый состояние нити на уровне операционной системы (например, пространства имён Linux или Plan 9), новый процесс унаследует состояние нити вызывающей стороны.
Пример
Код:
cmd := exec.Command("sleep", "1")
log.Printf("Running command and waiting for it to finish...")
err := cmd.Run()
log.Printf("Command finished with error: %v", err)
func (*Cmd) Start
func (c *Cmd) Start() error
Start запускает указанную команду, но не ждёт её завершения.
Если Start возвращает успешно, поле c.Process будет установлено.
После успешного вызова метода Cmd.Wait необходимо вызвать метод, чтобы освободить связанные системные ресурсы.
Пример
Код:
cmd := exec.Command("sleep", "5")
err := cmd.Start()
if err != nil {
log.Fatal(err)
}
log.Printf("Waiting for command to finish...")
err = cmd.Wait()
log.Printf("Command finished with error: %v", err)
func (*Cmd) StderrPipe
func (c *Cmd) StderrPipe() (io.ReadCloser, error)
StderrPipe возвращает канал, который будет подключен к стандартному ошибочному выводу команды при запуске команды.
Cmd.Wait закроет канал после завершения команды, поэтому большинству вызывающих функций не нужно закрывать канал самостоятельно. Таким образом, вызов Wait до завершения всех чтений из канала является некорректным. По этой же причине некорректно использовать Cmd.Run при использовании StderrPipe. См. пример StdoutPipe для правильного использования.
Пример
Код:
cmd := exec.Command("sh", "-c", "echo stdout; echo 1>&2 stderr")
stderr, err := cmd.StderrPipe()
if err != nil {
log.Fatal(err)
}
if err := cmd.Start(); err != nil {
log.Fatal(err)
}
slurp, _ := io.ReadAll(stderr)
fmt.Printf("%s\n", slurp)
if err := cmd.Wait(); err != nil {
log.Fatal(err)
}
func (*Cmd) StdinPipe
func (c *Cmd) StdinPipe() (io.WriteCloser, error)
StdinPipe возвращает канал, который будет подключен к стандартному вводу команды при запуске команды. Канал будет автоматически закрыт после того, как Cmd.Wait увидит завершение команды. Вызывающей функции достаточно вызвать Close, чтобы принудительно закрыть канал раньше. Например, если выполняемая команда не завершится, пока стандартный ввод не будет закрыт, вызывающая функция должна закрыть канал.
Пример
Код:
cmd := exec.Command("cat")
stdin, err := cmd.StdinPipe()
if err != nil {
log.Fatal(err)
}
go func() {
defer stdin.Close()
io.WriteString(stdin, "values written to stdin are passed to cmd's standard input")
}()
out, err := cmd.CombinedOutput()
if err != nil {
log.Fatal(err)
}
fmt.Printf("%s\n", out)
func (*Cmd) StdoutPipe
func (c *Cmd) StdoutPipe() (io.ReadCloser, error)
StdoutPipe возвращает канал, который будет подключен к стандартному выводу команды при запуске команды.
Cmd.Wait закроет канал после завершения команды, поэтому большинству вызывающих функций не нужно закрывать канал самостоятельно. Таким образом, вызов Wait до завершения всех чтений из канала является некорректным. По этой же причине некорректно вызывать Cmd.Run при использовании StdoutPipe. См. пример правильного использования.
Пример
Код:
cmd := exec.Command("echo", "-n", `{"Name": "Bob", "Age": 32}`)
stdout, err := cmd.StdoutPipe()
if err != nil {
log.Fatal(err)
}
if err := cmd.Start(); err != nil {
log.Fatal(err)
}
var person struct {
Name string
Age int
}
if err := json.NewDecoder(stdout).Decode(&person); err != nil {
log.Fatal(err)
}
if err := cmd.Wait(); err != nil {
log.Fatal(err)
}
fmt.Printf("%s is %d years old\n", person.Name, person.Age)
func (*Cmd) String 1.13
func (c *Cmd) String() string
String возвращает удобочитаемое описание c. Предназначено только для отладки. В частности, не подходит для использования в качестве входных данных для оболочки. Вывод String может отличаться в разных релизах Go.
func (*Cmd) Wait
func (c *Cmd) Wait() error
Wait ожидает завершения команды и завершения любого копирования в стандартный ввод или копирования из стандартного вывода или стандартного ошибочного вывода.
Команда должна быть запущена с помощью Cmd.Start.
Возвращаемая ошибка равна nil, если команда выполняется без проблем, без проблем копирует stdin, stdout и stderr и завершается с нулевым кодом выхода.
Если команда не выполняется или не завершается успешно, ошибка является типом *ExitError. Другие типы ошибок могут быть возвращены для проблем с вводом-выводом.
Если какой-либо из c.Stdin, c.Stdout или c.Stderr не является *os.File, Wait также ожидает завершения соответствующей петли ввода-вывода, копирующей данные в или из процесса.
Wait освобождает все ресурсы, связанные с Cmd.
тип Error
Error возвращается LookPath, когда не удается определить файл как исполняемый.
type Error struct {
// Name is the file name for which the error occurred.
Name string
// Err is the underlying error.
Err error
}
func (*Error) Error
func (e *Error) Error() string
func (*Error) Unwrap 1.13
func (e *Error) Unwrap() error
тип ExitError
ExitError сообщает об неудачном завершении команды.
type ExitError struct {
*os.ProcessState
// Stderr holds a subset of the standard error output from the
// Cmd.Output method if standard error was not otherwise being
// collected.
//
// If the error output is long, Stderr may contain only a prefix
// and suffix of the output, with the middle replaced with
// text about the number of omitted bytes.
//
// Stderr is provided for debugging, for inclusion in error messages.
// Users with other needs should redirect Cmd.Stderr as needed.
Stderr []byte // Go 1.6
}
func (*ExitError) Error
func (e *ExitError) Error() string
Подкаталоги
| Имя | Синопсис |
|---|---|
| .. | |
© Google, Inc.
Licensed under the Creative Commons Attribution License 3.0.
http://golang.org/pkg/os/exec/