Метод exec.Cmd.StdinPipe

Метод StdinPipe структуры exec.Cmd создает канал (pipe), который подключается к стандартному вводу запускаемого процесса. Он возвращает интерфейс io.WriteCloser, через который можно записывать данные в стандартный ввод процесса. Этот метод полезен, когда необходимо передать данные команде интерактивно или по частям, а не через аргументы командной строки. Важно закрыть канал после записи, чтобы процесс получил сигнал о завершении ввода.

Синтаксис

gocmd.StdinPipe()

Метод не принимает параметров и возвращает два значения: канал для записи с типом io.WriteCloser и ошибку типа error.

Простой пример использования

Давайте запустим команду grep и передадим ей текст через стандартный ввод для поиска подстроки:

gopackage main

import (
  "fmt"
  "io"
  "os/exec"
)

func main() {
  cmd := exec.Command("grep", "Go")
  stdin, err := cmd.StdinPipe()
  if err != nil {
    fmt.Println("Error creating stdin pipe:", err)
    return
  }

  go func() {
    defer stdin.Close()
    io.WriteString(stdin, "Hello Go\n")
    io.WriteString(stdin, "Hello World\n")
  }()

  out, err := cmd.CombinedOutput()
  if err != nil {
    fmt.Println("Error running command:", err)
    return
  }

  fmt.Println(string(out))
}

Результат выполнения кода:

go"Hello Go\n"

В этом примере мы создаем команду grep Go, открываем канал для записи в стандартный ввод, записываем две строки в горутине, а затем читаем вывод команды через CombinedOutput.

Передача данных из файла

Давайте прочитаем данные из файла и передадим их в стандартный ввод команды, используя метод StdinPipe:

gopackage main

import (
  "fmt"
  "io"
  "os"
  "os/exec"
)

func main() {
  file, err := os.Open("input.txt")
  if err != nil {
    fmt.Println("Error opening file:", err)
    return
  }
  defer file.Close()

  cmd := exec.Command("wc", "-l")
  stdin, err := cmd.StdinPipe()
  if err != nil {
    fmt.Println("Error creating stdin pipe:", err)
    return
  }

  go func() {
    defer stdin.Close()
    io.Copy(stdin, file)
  }()

  out, err := cmd.Output()
  if err != nil {
    fmt.Println("Error running command:", err)
    return
  }

  fmt.Println(string(out))
}

Результат выполнения кода (предполагается, что файл input.txt содержит 5 строк):

go"     5\n"

Здесь мы открываем файл и передаем его содержимое в стандартный ввод команды wc -l, которая подсчитывает количество строк.

Интерактивное взаимодействие с процессом

Давайте создадим простую программу, которая читает ввод от пользователя и передает его процессу через стандартный ввод, а затем читает ответ процесса:

gopackage main

import (
  "bufio"
  "fmt"
  "os"
  "os/exec"
)

func main() {
  cmd := exec.Command("cat")
  stdin, err := cmd.StdinPipe()
  if err != nil {
    fmt.Println("Error creating stdin pipe:", err)
    return
  }

  stdout, err := cmd.StdoutPipe()
  if err != nil {
    fmt.Println("Error creating stdout pipe:", err)
    return
  }

  if err := cmd.Start(); err != nil {
    fmt.Println("Error starting command:", err)
    return
  }

  go func() {
    scanner := bufio.NewScanner(os.Stdin)
    for scanner.Scan() {
      line := scanner.Text()
      if line == "exit" {
        break
      }
      stdin.Write([]byte(line + "\n"))
    }
    stdin.Close()
  }()

  output := make([]byte, 1024)
  n, err := stdout.Read(output)
  if err == nil {
    fmt.Println(string(output[:n]))
  }

  cmd.Wait()
}

При выполнении этого кода пользователь может вводить строки, которые будут переданы команде cat, и получать их обратно. Для выхода из программы нужно ввести слово exit.

Смотрите также

  • метод exec.Cmd.StdoutPipe,
    который возвращает канал для чтения стандартного вывода процесса
  • метод exec.Cmd.StderrPipe,
    который возвращает канал для чтения стандартного вывода ошибок процесса
  • метод exec.Cmd.Output,
    который запускает команду и возвращает ее стандартный вывод
  • метод exec.Cmd.CombinedOutput,
    который запускает команду и возвращает объединенный вывод