Spec-Zone.ru › Ruby 3.3

модуль Open3

Модуль Open3 поддерживает создание дочерних процессов с доступом к потокам $stdin, $stdout и $stderr.

Что здесь

Каждый из этих методов выполняет заданную команду в новом процессе или подоболочке, или несколько команд в новых процессах и/или подоболочках:

  • Каждый из этих методов выполняет одну команду в процессе или подоболочке, принимает строку для ввода в $stdin и возвращает строку вывода из $stdout, $stderr или обоих:

    • Open3.capture2: Выполняет команду; возвращает строку из $stdout.

    • Open3.capture2e: Выполняет команду; возвращает строку из объединённых $stdout и $stderr.

    • Open3.capture3: Выполняет команду; возвращает строки из $stdout и $stderr.

  • Каждый из этих методов выполняет одну команду в процессе или подоболочке и возвращает каналы для $stdin, $stdout и/или $stderr:

    • Open3.popen2: Выполняет команду; возвращает каналы для $stdin и $stdout.

    • Open3.popen2e: Выполняет команду; возвращает каналы для $stdin и объединённых $stdout и $stderr.

    • Open3.popen3: Выполняет команду; возвращает каналы для $stdin, $stdout и $stderr.

  • Каждый из этих методов выполняет одну или несколько команд в процессах и/или подоболочках, возвращает каналы для первого $stdin, последнего $stdout или обоих:

    • Open3.pipeline_r: Возвращает канал для последнего $stdout.

    • Open3.pipeline_rw: Возвращает каналы для первого $stdin и последнего $stdout.

    • Open3.pipeline_w: Возвращает канал для первого $stdin.

    • Open3.pipeline_start: Не ожидает завершения процессов.

    • Open3.pipeline: Ожидает завершения процессов.

Каждый из вышеперечисленных методов принимает:

  • Необязательный хеш имён и значений переменных среды; см. Окружение выполнения.

  • Обязательный строковый аргумент, который является command_line или exe_path; см. Аргумент command_line или exe_path.

  • Необязательный хеш опций выполнения; см. Опции выполнения.

Константы

VERSION

Публичные методы класса

capture2([env, ] command_line, options = {}) → [stdout_s, status] Показать исходный код
capture2([env, ] exe_path, *args, options = {}) → [stdout_s, status]
# File lib/open3.rb, line 775
def capture2(*cmd)
  if Hash === cmd.last
    opts = cmd.pop.dup
  else
    opts = {}
  end

  stdin_data = opts.delete(:stdin_data)
  binmode = opts.delete(:binmode)

  popen2(*cmd, opts) {|i, o, t|
    if binmode
      i.binmode
      o.binmode
    end
    out_reader = Thread.new { o.read }
    if stdin_data
      begin
        if stdin_data.respond_to? :readpartial
          IO.copy_stream(stdin_data, i)
        else
          i.write stdin_data
        end
      rescue Errno::EPIPE
      end
    end
    i.close
    [out_reader.value, t.value]
  }
end

В основном, это обертка для Open3.popen3, которая:

  • Создаёт дочерний процесс, вызывая Open3.popen3 с заданными аргументами (за исключением определённых элементов в хеше options; см. ниже).

  • Возвращает строку stdout_s стандартного вывода дочернего процесса.

  • Возвращает в качестве status объект Process::Status, представляющий статус завершения дочернего процесса.

Возвращает массив [stdout_s, status]:

stdout_s, status = Open3.capture2('echo "Foo"')
# => ["Foo\n", #<Process::Status: pid 2326047 exit 0>]

Как и Process.spawn, этот метод имеет потенциальные уязвимости в безопасности, если вызывается с недоверенным вводом; см. Внедрение команд.

В отличие от Process.spawn, этот метод ожидает завершения дочернего процесса перед возвратом, поэтому вызывающий код не должен этого делать.

Если первый аргумент — хеш, он становится ведущим аргументом env в вызове Open3.popen3; см. Окружение выполнения.

Если последний аргумент — хеш, он становится конечным аргументом options в вызове Open3.popen3; см. Опции выполнения.

Хеш options задаётся; две опции имеют локальный эффект в методе Open3.capture2:

  • Если элемент options[:stdin_data] существует, элемент удаляется, и его строковое значение отправляется на стандартный ввод команды:

    Open3.capture2('tee', stdin_data: 'Foo')
    
    # => ["Foo", #<Process::Status: pid 2326087 exit 0>]
    
  • Если элемент options[:binmode] существует, элемент удаляется, и внутренние потоки устанавливаются в бинарный режим.

Одиночный обязательный аргумент может быть одним из следующих:

  • command_line если это строка, и если она начинается со служебного слова оболочки или специального встроенного или содержит один или несколько метасимволов.

  • exe_path в противном случае.

Аргумент command_line

Строковый аргумент command_line — это командная строка, передаваемая оболочке; она должна начинаться со служебного слова оболочки, начинаться со специального встроенного или содержать метасимволы:

Open3.capture2('if true; then echo "Foo"; fi') # Shell reserved word.
# => ["Foo\n", #<Process::Status: pid 2326131 exit 0>]
Open3.capture2('echo')                         # Built-in.
# => ["\n", #<Process::Status: pid 2326139 exit 0>]
Open3.capture2('date > date.tmp')              # Contains meta character.
# => ["", #<Process::Status: pid 2326174 exit 0>]

Командная строка также может содержать аргументы и опции для команды:

Open3.capture2('echo "Foo"')
# => ["Foo\n", #<Process::Status: pid 2326183 exit 0>]

Аргумент exe_path

Аргумент exe_path может быть одним из следующих:

  • Путь к исполняемому файлу, который нужно вызвать.

  • Массив из 2 элементов, содержащий путь к исполняемому файлу и строку, которая будет использоваться в качестве имени выполняемого процесса.

Пример:

Open3.capture2('/usr/bin/date')
# => ["Fri Sep 29 01:00:39 PM CDT 2023\n", #<Process::Status: pid 2326222 exit 0>]

Ruby вызывает исполняемый файл напрямую, без оболочки и без расширения оболочки:

Open3.capture2('doesnt_exist') # Raises Errno::ENOENT

Если задан один или несколько args, каждый из них является аргументом или опцией, которые будут переданы исполняемому файлу:

Open3.capture2('echo', 'C #')
# => ["C #\n", #<Process::Status: pid 2326267 exit 0>]
Open3.capture2('echo', 'hello', 'world')
# => ["hello world\n", #<Process::Status: pid 2326299 exit 0>]
capture2e([env, ] command_line, options = {}) → [stdout_and_stderr_s, status] Показать исходный код
capture2e([env, ] exe_path, *args, options = {}) → [stdout_and_stderr_s, status]
# File lib/open3.rb, line 902
def capture2e(*cmd)
  if Hash === cmd.last
    opts = cmd.pop.dup
  else
    opts = {}
  end

  stdin_data = opts.delete(:stdin_data)
  binmode = opts.delete(:binmode)

  popen2e(*cmd, opts) {|i, oe, t|
    if binmode
      i.binmode
      oe.binmode
    end
    outerr_reader = Thread.new { oe.read }
    if stdin_data
      begin
        if stdin_data.respond_to? :readpartial
          IO.copy_stream(stdin_data, i)
        else
          i.write stdin_data
        end
      rescue Errno::EPIPE
      end
    end
    i.close
    [outerr_reader.value, t.value]
  }
end

В основном, это обертка для Open3.popen3, которая:

  • Создаёт дочерний процесс, вызывая Open3.popen3 с заданными аргументами (за исключением определённых элементов в хеше options; см. ниже).

  • Возвращает строку stdout_and_stderr_s объединённого стандартного вывода и стандартной ошибки дочернего процесса.

  • Возвращает в качестве status объект Process::Status, представляющий статус завершения дочернего процесса.

Возвращает массив [stdout_and_stderr_s, status]:

stdout_and_stderr_s, status = Open3.capture2e('echo "Foo"')
# => ["Foo\n", #<Process::Status: pid 2371692 exit 0>]

Как и Process.spawn, этот метод имеет потенциальные уязвимости в безопасности, если вызывается с недоверенным вводом; см. Внедрение команд.

В отличие от Process.spawn, этот метод ожидает завершения дочернего процесса перед возвратом, поэтому вызывающий код не должен этого делать.

Если первый аргумент — хеш, он становится ведущим аргументом env в вызове Open3.popen3; см. Окружение выполнения.

Если последний аргумент — хеш, он становится конечным аргументом options в вызове Open3.popen3; см. Опции выполнения.

Хеш options задаётся; две опции имеют локальный эффект в методе Open3.capture2e:

  • Если элемент options[:stdin_data] существует, элемент удаляется, и его строковое значение отправляется на стандартный ввод команды:

    Open3.capture2e('tee', stdin_data: 'Foo')
    # => ["Foo", #<Process::Status: pid 2371732 exit 0>]
    
  • Если элемент options[:binmode] существует, элемент удаляется, и внутренние потоки устанавливаются в бинарный режим.

Одиночный обязательный аргумент может быть одним из следующих:

  • command_line если это строка, и если она начинается со служебного слова оболочки или специального встроенного или содержит один или несколько метасимволов.

  • exe_path в противном случае.

Аргумент command_line

Строковый аргумент command_line — это командная строка, передаваемая оболочке; она должна начинаться со служебного слова оболочки, начинаться со специального встроенного или содержать метасимволы:

Open3.capture2e('if true; then echo "Foo"; fi') # Shell reserved word.
# => ["Foo\n", #<Process::Status: pid 2371740 exit 0>]
Open3.capture2e('echo')                         # Built-in.
# => ["\n", #<Process::Status: pid 2371774 exit 0>]
Open3.capture2e('date > date.tmp')              # Contains meta character.
# => ["", #<Process::Status: pid 2371812 exit 0>]

Командная строка также может содержать аргументы и опции для команды:

Open3.capture2e('echo "Foo"')
# => ["Foo\n", #<Process::Status: pid 2326183 exit 0>]

Аргумент exe_path

Аргумент exe_path может быть одним из следующих:

  • Путь к исполняемому файлу, который нужно вызвать.

  • Массив из 2 элементов, содержащий путь к исполняемому файлу и строку, которая будет использоваться в качестве имени выполняемого процесса.

Пример:

Open3.capture2e('/usr/bin/date')
# => ["Sat Sep 30 09:01:46 AM CDT 2023\n", #<Process::Status: pid 2371820 exit 0>]

Ruby вызывает исполняемый файл напрямую, без оболочки и без расширения оболочки:

Open3.capture2e('doesnt_exist') # Raises Errno::ENOENT

Если задан один или несколько args, каждый из них является аргументом или опцией, которые будут переданы исполняемому файлу:

Open3.capture2e('echo', 'C #')
# => ["C #\n", #<Process::Status: pid 2371856 exit 0>]
Open3.capture2e('echo', 'hello', 'world')
# => ["hello world\n", #<Process::Status: pid 2371894 exit 0>]
capture3([env, ] command_line, options = {}) → [stdout_s, stderr_s, status] Показать исходный код
capture3([env, ] exe_path, *args, options = {}) → [stdout_s, stderr_s, status]
# File lib/open3.rb, line 648
def capture3(*cmd)
  if Hash === cmd.last
    opts = cmd.pop.dup
  else
    opts = {}
  end

  stdin_data = opts.delete(:stdin_data) || ''
  binmode = opts.delete(:binmode)

  popen3(*cmd, opts) {|i, o, e, t|
    if binmode
      i.binmode
      o.binmode
      e.binmode
    end
    out_reader = Thread.new { o.read }
    err_reader = Thread.new { e.read }
    begin
      if stdin_data.respond_to? :readpartial
        IO.copy_stream(stdin_data, i)
      else
        i.write stdin_data
      end
    rescue Errno::EPIPE
    end
    i.close
    [out_reader.value, err_reader.value, t.value]
  }
end

В основном это обёртка для Open3.popen3, которая:

  • Создаёт дочерний процесс, вызывая Open3.popen3 с заданными аргументами (кроме определённых записей в хэше options; см. ниже).

  • Возвращает в виде строк stdout_s и stderr_s стандартный вывод и стандартную ошибку дочернего процесса.

  • Возвращает в виде status объект Process::Status, представляющий код возврата дочернего процесса.

Возвращает массив [stdout_s, stderr_s, status]:

stdout_s, stderr_s, status = Open3.capture3('echo "Foo"')
# => ["Foo\n", "", #<Process::Status: pid 2281954 exit 0>]

Как и метод Process.spawn, этот метод имеет потенциальные уязвимости в области безопасности, если вызван с недоверенным вводом; см. Внедрение команд.

В отличие от Process.spawn, этот метод ожидает завершения дочернего процесса перед возвратом, поэтому вызывающей стороне не нужно этого делать.

Если первый аргумент является хэшем, он становится ведущим аргументом env при вызове Open3.popen3; см. Выполняющая среда.

Если последний аргумент является хэшем, он становится заключительным аргументом options при вызове Open3.popen3; см. Параметры выполнения.

Хэш options задан; два параметра имеют локальное влияние в методе Open3.capture3:

  • Если существует запись options[:stdin_data], запись удаляется, а её строковое значение отправляется на стандартный ввод команды:

    Open3.capture3('tee', stdin_data: 'Foo')
    # => ["Foo", "", #<Process::Status: pid 2319575 exit 0>]
    
  • Если существует запись options[:binmode], запись удаляется, а внутренние потоки устанавливаются в двоичный режим.

Единственный обязательный аргумент — это один из следующих:

  • command_line если это строка, и если она начинается с зарезервированного слова оболочки или специального встроенного, или если она содержит один или несколько метасимволов.

  • exe_path в противном случае.

Аргумент command_line

Строковый аргумент command_line — это командная строка, которая будет передана оболочке; она должна начинаться с зарезервированного слова оболочки, начинаться со специального встроенного или содержать метасимволы:

Open3.capture3('if true; then echo "Foo"; fi') # Shell reserved word.
# => ["Foo\n", "", #<Process::Status: pid 2282025 exit 0>]
Open3.capture3('echo')                         # Built-in.
# => ["\n", "", #<Process::Status: pid 2282092 exit 0>]
Open3.capture3('date > date.tmp')              # Contains meta character.
# => ["", "", #<Process::Status: pid 2282110 exit 0>]

Командная строка также может содержать аргументы и параметры для команды:

Open3.capture3('echo "Foo"')
# => ["Foo\n", "", #<Process::Status: pid 2282092 exit 0>]

Аргумент exe_path

Аргумент exe_path — это один из следующих:

  • Путь к исполняемому файлу, который нужно вызвать.

  • Массив из 2 элементов, содержащий путь к исполняемому файлу и строку, которая будет использоваться в качестве имени выполняемого процесса.

Пример:

Open3.capture3('/usr/bin/date')
# => ["Thu Sep 28 05:03:51 PM CDT 2023\n", "", #<Process::Status: pid 2282300 exit 0>]

Ruby вызывает исполняемый файл непосредственно, без оболочки и без расширения оболочки:

Open3.capture3('doesnt_exist') # Raises Errno::ENOENT

Если задан один или несколько args, каждый из них — это аргумент или параметр, который должен быть передан исполняемому файлу:

Open3.capture3('echo', 'C #')
# => ["C #\n", "", #<Process::Status: pid 2282368 exit 0>]
Open3.capture3('echo', 'hello', 'world')
# => ["hello world\n", "", #<Process::Status: pid 2282372 exit 0>]
pipeline([env, ] *cmds, options = {}) → array_of_statuses Показать исходный код
# File lib/open3.rb, line 1334
def pipeline(*cmds)
  if Hash === cmds.last
    opts = cmds.pop.dup
  else
    opts = {}
  end

  pipeline_run(cmds, opts, [], []) {|ts|
    ts.map(&:value)
  }
end

В основном это обёртка для Process.spawn, которая:

  • Создаёт дочерний процесс для каждого из заданных cmds с помощью вызова Process.spawn.

  • Перенаправляет stdout от каждого дочернего процесса в stdin следующего дочернего процесса или, для последнего дочернего процесса, в stdout вызывающей стороны.

  • Ожидает завершения дочерних процессов.

  • Возвращает массив объектов Process::Status (по одному для каждого дочернего процесса).

Пример:

wait_threads = Open3.pipeline('ls', 'grep R')
# => [#<Process::Status: pid 2139200 exit 0>, #<Process::Status: pid 2139202 exit 0>]

Вывод:

Rakefile
README.md

Как и Process.spawn, этот метод имеет потенциальные уязвимости в области безопасности, если вызван с недоверенным вводом; см. Внедрение команд.

Если первый аргумент является хэшем, он становится ведущим аргументом env в каждом вызове Process.spawn; см. Выполняющая среда.

Если последний аргумент является хэшем, он становится заключительным аргументом options в каждом вызове Process.spawn; см. Параметры выполнения.

Каждый оставшийся аргумент в cmds — это:

  • Командная строка: строка, начинающаяся с зарезервированного слова оболочки или специального встроенного, или содержащая один или несколько метасимволов.

  • Путь к исполняемому файлу: строка пути к вызываемому исполняемому файлу.

  • Массив, содержащий командную строку или путь к исполняемому файлу, а также ноль или более строковых аргументов для команды.

См. Аргумент command_line или exe_path.

pipeline_r([env, ] *cmds, options = {}) → [last_stdout, wait_threads] Показать исходный код
# File lib/open3.rb, line 1104
def pipeline_r(*cmds, &block)
  if Hash === cmds.last
    opts = cmds.pop.dup
  else
    opts = {}
  end

  out_r, out_w = IO.pipe
  opts[:out] = out_w

  pipeline_run(cmds, opts, [out_w], [out_r], &block)
end

В основном это обёртка для Process.spawn, которая:

  • Создаёт дочерний процесс для каждого из заданных cmds с помощью вызова Process.spawn.

  • Перенаправляет stdout от каждого дочернего процесса в stdin следующего дочернего процесса или, для последнего дочернего процесса, в stdout вызывающей стороны.

Метод не ожидает завершения дочерних процессов, поэтому вызывающая сторона должна сделать это.

Без блока возвращает массив из 2 элементов, содержащий:

  • Поток stdout последнего дочернего процесса.

  • Массив потоков ожидания для всех дочерних процессов.

Пример:

last_stdout, wait_threads = Open3.pipeline_r('ls', 'grep R')
# => [#<IO:fd 5>, [#<Process::Waiter:0x000055e8de2f9898 dead>, #<Process::Waiter:0x000055e8de2f94b0 sleep>]]
puts last_stdout.read
wait_threads.each do |wait_thread|
  wait_thread.join
end

Вывод:

Rakefile
README.md

При указанном блоке вызывает блок с потоком stdout последнего дочернего процесса и массивом потоков ожидания:

Open3.pipeline_r('ls', 'grep R') do |last_stdout, wait_threads|
  puts last_stdout.read
  wait_threads.each do |wait_thread|
    wait_thread.join
  end
end

Вывод:

Rakefile
README.md

Как и Process.spawn, этот метод имеет потенциальные уязвимости в области безопасности, если вызван с недоверенным вводом; см. Внедрение команд.

Если первый аргумент является хэшем, он становится ведущим аргументом env в каждом вызове Process.spawn; см. Выполняющая среда.

Если последний аргумент является хэшем, он становится заключительным аргументом options в каждом вызове Process.spawn; см. Параметры выполнения.

Каждый оставшийся аргумент в cmds — это:

  • Командная строка: строка, начинающаяся с зарезервированного слова оболочки или специального встроенного, или содержащая один или несколько метасимволов.

  • Путь к исполняемому файлу: строка пути к вызываемому исполняемому файлу.

  • Массив, содержащий командную строку или путь к исполняемому файлу, а также ноль или более строковых аргументов для команды.

См. Аргумент command_line или exe_path.

pipeline_rw([env, ] *cmds, options = {}) → [first_stdin, last_stdout, wait_threads] Показать исходный код
# File lib/open3.rb, line 1014
def pipeline_rw(*cmds, &block)
  if Hash === cmds.last
    opts = cmds.pop.dup
  else
    opts = {}
  end

  in_r, in_w = IO.pipe
  opts[:in] = in_r
  in_w.sync = true

  out_r, out_w = IO.pipe
  opts[:out] = out_w

  pipeline_run(cmds, opts, [in_r, out_w], [in_w, out_r], &block)
end

В основном это обёртка для Process.spawn, которая:

  • Создаёт дочерний процесс для каждого из заданных cmds с помощью вызова Process.spawn.

  • Перенаправляет stdout от каждого дочернего процесса к stdin следующего дочернего процесса, или, для первого дочернего процесса, от входного потока вызывающего процесса, или, для последнего дочернего процесса, во входной поток вызывающего процесса.

Метод не ждёт завершения дочерних процессов, поэтому вызывающий процесс должен сделать это самостоятельно.

Без блока возвращает массив из 3 элементов, содержащий:

  • Поток stdin первого дочернего процесса.

  • Поток stdout последнего дочернего процесса.

  • Массив потоков ожидания для всех дочерних процессов.

Пример:

first_stdin, last_stdout, wait_threads = Open3.pipeline_rw('sort', 'cat -n')
# => [#<IO:fd 20>, #<IO:fd 21>, [#<Process::Waiter:0x000055e8de29ab40 sleep>, #<Process::Waiter:0x000055e8de29a690 sleep>]]
first_stdin.puts("foo\nbar\nbaz")
first_stdin.close # Send EOF to sort.
puts last_stdout.read
wait_threads.each do |wait_thread|
  wait_thread.join
end

Вывод:

1 bar
2 baz
3 foo

С блоком вызывается блок с потоком stdin первого дочернего процесса, потоком stdout последнего дочернего процесса и массивом потоков ожидания:

Open3.pipeline_rw('sort', 'cat -n') do |first_stdin, last_stdout, wait_threads|
  first_stdin.puts "foo\nbar\nbaz"
  first_stdin.close # send EOF to sort.
  puts last_stdout.read
  wait_threads.each do |wait_thread|
    wait_thread.join
  end
end

Вывод:

1 bar
2 baz
3 foo

Как и Process.spawn, этот метод имеет потенциальные уязвимости безопасности при вызове с недоверенными данными; см. Инъекция команд.

Если первый аргумент является хешем, он становится ведущим аргументом env в каждом вызове Process.spawn; см. Окружение выполнения.

Если последний аргумент является хешем, он становится хвостовым аргументом options в каждом вызове Process.spawn; см. Параметры выполнения.

Каждый оставшийся аргумент в cmds является одним из:

  • command_line: строка, начинающаяся с зарезервированного слова оболочки или специального встроенного компонента, или содержащая один или несколько метасимволов.

  • exe_path: строковый путь к исполняемому файлу, который необходимо вызвать.

  • Массив, содержащий command_line или exe_path, а также ноль или более строковых аргументов для команды.

См. Аргумент command_line или exe_path.

pipeline_start([env, ] *cmds, options = {}) → [wait_threads] Показать исходный код
# File lib/open3.rb, line 1272
def pipeline_start(*cmds, &block)
  if Hash === cmds.last
    opts = cmds.pop.dup
  else
    opts = {}
  end

  if block
    pipeline_run(cmds, opts, [], [], &block)
  else
    ts, = pipeline_run(cmds, opts, [], [])
    ts
  end
end

В основном это обёртка для Process.spawn, которая:

  • Создаёт дочерний процесс для каждого из заданных cmds с помощью вызова Process.spawn.

  • Не ждёт завершения дочерних процессов.

Без блока возвращает массив потоков ожидания для всех дочерних процессов.

Пример:

wait_threads = Open3.pipeline_start('ls', 'grep R')
# => [#<Process::Waiter:0x000055e8de9d2bb0 run>, #<Process::Waiter:0x000055e8de9d2890 run>]
wait_threads.each do |wait_thread|
  wait_thread.join
end

Вывод:

Rakefile
README.md

С блоком вызывается блок с массивом потоков ожидания:

Open3.pipeline_start('ls', 'grep R') do |wait_threads|
  wait_threads.each do |wait_thread|
    wait_thread.join
  end
end

Вывод:

Rakefile
README.md

Как и Process.spawn, этот метод имеет потенциальные уязвимости безопасности при вызове с недоверенными данными; см. Инъекция команд.

Если первый аргумент является хешем, он становится ведущим аргументом env в каждом вызове Process.spawn; см. Окружение выполнения.

Если последний аргумент является хешем, он становится хвостовым аргументом options в каждом вызове Process.spawn; см. Параметры выполнения.

Каждый оставшийся аргумент в cmds является одним из:

  • command_line: строка, начинающаяся с зарезервированного слова оболочки или специального встроенного компонента, или содержащая один или несколько метасимволов.

  • exe_path: строковый путь к исполняемому файлу, который необходимо вызвать.

  • Массив, содержащий command_line или exe_path, а также ноль или более строковых аргументов для команды.

См. Аргумент command_line или exe_path.

pipeline_w([env, ] *cmds, options = {}) → [first_stdin, wait_threads] Показать исходный код
# File lib/open3.rb, line 1195
def pipeline_w(*cmds, &block)
  if Hash === cmds.last
    opts = cmds.pop.dup
  else
    opts = {}
  end

  in_r, in_w = IO.pipe
  opts[:in] = in_r
  in_w.sync = true

  pipeline_run(cmds, opts, [in_r], [in_w], &block)
end

В основном это обёртка для Process.spawn, которая:

  • Создаёт дочерний процесс для каждого из заданных cmds с помощью вызова Process.spawn.

  • Перенаправляет stdout от каждого дочернего процесса к stdin следующего дочернего процесса, или, для первого дочернего процесса, перенаправляет входной поток вызывающего процесса к входному потоку дочернего процесса.

Метод не ждёт завершения дочерних процессов, поэтому вызывающий процесс должен сделать это самостоятельно.

Без блока возвращает массив из 2 элементов, содержащий:

  • Поток stdin первого дочернего процесса.

  • Массив потоков ожидания для всех дочерних процессов.

Пример:

first_stdin, wait_threads = Open3.pipeline_w('sort', 'cat -n')
# => [#<IO:fd 7>, [#<Process::Waiter:0x000055e8de928278 run>, #<Process::Waiter:0x000055e8de923e80 run>]]
first_stdin.puts("foo\nbar\nbaz")
first_stdin.close # Send EOF to sort.
wait_threads.each do |wait_thread|
  wait_thread.join
end

Вывод:

1 bar
2 baz
3 foo

С блоком вызывается блок с потоком stdin первого дочернего процесса и массивом потоков ожидания:

Open3.pipeline_w('sort', 'cat -n') do |first_stdin, wait_threads|
  first_stdin.puts("foo\nbar\nbaz")
  first_stdin.close # Send EOF to sort.
  wait_threads.each do |wait_thread|
    wait_thread.join
  end
end

Вывод:

1 bar
2 baz
3 foo

Как и Process.spawn, этот метод имеет потенциальные уязвимости безопасности при вызове с недоверенными данными; см. Инъекция команд.

Если первый аргумент является хешем, он становится ведущим аргументом env в каждом вызове Process.spawn; см. Окружение выполнения.

Если последний аргумент является хешем, он становится хвостовым аргументом options в каждом вызове Process.spawn; см. Параметры выполнения.

Каждый оставшийся аргумент в cmds является одним из:

  • command_line: строка, начинающаяся с зарезервированного слова оболочки или специального встроенного компонента, или содержащая один или несколько метасимволов.

  • exe_path: строковый путь к исполняемому файлу, который необходимо вызвать.

  • Массив, содержащий command_line или exe_path, а также ноль или более строковых аргументов для команды.

См. Аргумент command_line или exe_path.

popen2([env, ] command_line, options = {}) → [stdin, stdout, wait_thread] Показать исходный код
popen2([env, ] exe_path, *args, options = {}) → [stdin, stdout, wait_thread]
popen2([env, ] command_line, options = {}) {|stdin, stdout, wait_thread| ... } → object
popen2([env, ] exe_path, *args, options = {}) {|stdin, stdout, wait_thread| ... } → object
# File lib/open3.rb, line 365
def popen2(*cmd, &block)
  if Hash === cmd.last
    opts = cmd.pop.dup
  else
    opts = {}
  end

  in_r, in_w = IO.pipe
  opts[:in] = in_r
  in_w.sync = true

  out_r, out_w = IO.pipe
  opts[:out] = out_w

  popen_run(cmd, opts, [in_r, out_w], [in_w, out_r], &block)
end

В основном это обёртка для Process.spawn, которая:

  • Создаёт дочерний процесс, вызывая Process.spawn с заданными аргументами.

  • Создаёт потоки stdin и stdout, которые являются стандартными потоками ввода и вывода дочернего процесса.

  • Создаёт поток wait_thread, который ждёт завершения дочернего процесса; этот поток имеет метод pid, возвращающий идентификатор процесса дочернего процесса.

Без блока возвращает массив [stdin, stdout, wait_thread]. Вызывающий код должен закрыть каждый из двух возвращённых потоков.

stdin, stdout, wait_thread = Open3.popen2('echo')
# => [#<IO:fd 6>, #<IO:fd 7>, #<Process::Waiter:0x00007f58d52dbe98 run>]
stdin.close
stdout.close
wait_thread.pid   # => 2263572
wait_thread.value # => #<Process::Status: pid 2263572 exit 0>

С блоком вызов передаёт три переменные (два потока и поток ожидания) в блок и возвращает значение, возвращённое блоком. Вызывающий код потоки закрывать не должен:

Open3.popen2('echo') do |stdin, stdout, wait_thread|
  p stdin
  p stdout
  p wait_thread
  p wait_thread.pid
  p wait_thread.value
end

Вывод:

#<IO:fd 6>
#<IO:fd 7>
#<Process::Waiter:0x00007f58d59a34b0 sleep>
2263636
#<Process::Status: pid 2263636 exit 0>

Как и Process.spawn, этот метод имеет потенциальные уязвимости в случае использования недоверенных данных; см. Ввод команд.

В отличие от Process.spawn, этот метод ждёт завершения дочернего процесса перед возвратом, поэтому вызывающий код это делать не обязан.

Если первый аргумент — хеш, он становится ведущим аргументом env в вызове Process.spawn; см. Окружение выполнения.

Если последний аргумент — хеш, он становится хвостовым аргументом options в вызове Process.spawn; см. Параметры выполнения.

Единственный обязательный аргумент может быть одним из следующих:

  • command_line если это строка, начинающаяся с зарезервированного слова оболочки или специального встроенного, или содержащая один или несколько метасимволов.

  • exe_path в противном случае.

Аргумент command_line

Строковый аргумент command_line — это командная строка, передаваемая оболочке; она должна начинаться с зарезервированного слова оболочки, специального встроенного или содержать метасимволы:

Open3.popen2('if true; then echo "Foo"; fi') {|*args| p args } # Shell reserved word.
Open3.popen2('echo') {|*args| p args }                         # Built-in.
Open3.popen2('date > date.tmp') {|*args| p args }              # Contains meta character.

Вывод (аналогично для каждого вызова выше):

# => [#<IO:(closed)>, #<IO:(closed)>, #<Process::Waiter:0x00007f7577dfe410 dead>]

Командная строка также может содержать аргументы и параметры для команды:

Open3.popen2('echo "Foo"') { |i, o, t| o.gets }
"Foo\n"

Аргумент exe_path

Аргумент exe_path может быть одним из следующих:

  • Путь к исполняемому файлу, который нужно вызвать.

  • Массив из двух элементов, содержащий путь к исполняемому файлу и строку, используемую в качестве имени выполняемого процесса.

Пример:

Open3.popen2('/usr/bin/date') { |i, o, t| o.gets }
# => "Thu Sep 28 09:41:06 AM CDT 2023\n"

Ruby вызывает исполняемый файл непосредственно, без оболочки и без расширения оболочки:

Open3.popen2('doesnt_exist') { |i, o, t| o.gets } # Raises Errno::ENOENT

Если задано одно или несколько args, каждое из них является аргументом или параметром, передаваемым исполняемому файлу:

Open3.popen2('echo', 'C #') { |i, o, t| o.gets }
# => "C #\n"
Open3.popen2('echo', 'hello', 'world') { |i, o, t| o.gets }
# => "hello world\n"

Связанное:

  • Open3.popen2e: Делает стандартный ввод и объединение стандартного вывода и стандартной ошибки дочернего процесса доступными как отдельные потоки.

  • Open3.popen3: Делает стандартные потоки ввода, вывода и ошибки дочернего процесса доступными как отдельные потоки.

popen2e([env, ] command_line, options = {}) → [stdin, stdout_and_stderr, wait_thread] Показать исходный код
popen2e([env, ] exe_path, *args, options = {}) → [stdin, stdout_and_stderr, wait_thread]
popen2e([env, ] command_line, options = {}) {|stdin, stdout_and_stderr, wait_thread| ... } → object
popen2e([env, ] exe_path, *args, options = {}) {|stdin, stdout_and_stderr, wait_thread| ... } → object
# File lib/open3.rb, line 508
def popen2e(*cmd, &block)
  if Hash === cmd.last
    opts = cmd.pop.dup
  else
    opts = {}
  end

  in_r, in_w = IO.pipe
  opts[:in] = in_r
  in_w.sync = true

  out_r, out_w = IO.pipe
  opts[[:out, :err]] = out_w

  popen_run(cmd, opts, [in_r, out_w], [in_w, out_r], &block)
ensure
  if block
    in_r.close
    in_w.close
    out_r.close
    out_w.close
  end
end

В основном это обёртка для Process.spawn, которая:

  • Создаёт дочерний процесс, вызывая Process.spawn с заданными аргументами.

  • Создаёт потоки stdin, stdout_and_stderr, которые являются стандартным потоком ввода и объединением потоков стандартного вывода и стандартной ошибки дочернего процесса.

  • Создаёт поток wait_thread, который ждёт завершения дочернего процесса; этот поток имеет метод pid, возвращающий идентификатор процесса дочернего процесса.

Без блока возвращает массив [stdin, stdout_and_stderr, wait_thread]. Вызывающий код должен закрыть каждый из двух возвращённых потоков.

stdin, stdout_and_stderr, wait_thread = Open3.popen2e('echo')
# => [#<IO:fd 6>, #<IO:fd 7>, #<Process::Waiter:0x00007f7577da4398 run>]
stdin.close
stdout_and_stderr.close
wait_thread.pid   # => 2274600
wait_thread.value # => #<Process::Status: pid 2274600 exit 0>

С блоком вызов передаёт три переменные (два потока и поток ожидания) в блок и возвращает значение, возвращённое блоком. Вызывающий код потоки закрывать не должен:

Open3.popen2e('echo') do |stdin, stdout_and_stderr, wait_thread|
  p stdin
  p stdout_and_stderr
  p wait_thread
  p wait_thread.pid
  p wait_thread.value
end

Вывод:

#<IO:fd 6>
#<IO:fd 7>
#<Process::Waiter:0x00007f75777578c8 sleep>
2274763
#<Process::Status: pid 2274763 exit 0>

Как и Process.spawn, этот метод имеет потенциальные уязвимости в случае использования недоверенных данных; см. Ввод команд.

В отличие от Process.spawn, этот метод ждёт завершения дочернего процесса перед возвратом, поэтому вызывающий код это делать не обязан.

Если первый аргумент — хеш, он становится ведущим аргументом env в вызове Process.spawn; см. Окружение выполнения.

Если последний аргумент — хеш, он становится хвостовым аргументом options в вызове Process.spawn; см. Параметры выполнения.

Единственный обязательный аргумент может быть одним из следующих:

  • command_line если это строка, начинающаяся с зарезервированного слова оболочки или специального встроенного, или содержащая один или несколько метасимволов.

  • exe_path в противном случае.

Аргумент command_line

Строковый аргумент command_line — это командная строка, передаваемая оболочке; она должна начинаться с зарезервированного слова оболочки, специального встроенного или содержать метасимволы:

Open3.popen2e('if true; then echo "Foo"; fi') {|*args| p args } # Shell reserved word.
Open3.popen2e('echo') {|*args| p args }                         # Built-in.
Open3.popen2e('date > date.tmp') {|*args| p args }              # Contains meta character.

Вывод (аналогично для каждого вызова выше):

# => [#<IO:(closed)>, #<IO:(closed)>, #<Process::Waiter:0x00007f7577d8a1f0 dead>]

Командная строка также может содержать аргументы и параметры для команды:

Open3.popen2e('echo "Foo"') { |i, o_and_e, t| o_and_e.gets }
"Foo\n"

Аргумент exe_path

Аргумент exe_path может быть одним из следующих:

  • Путь к исполняемому файлу, который нужно вызвать.

  • Массив из двух элементов, содержащий путь к исполняемому файлу и строку, используемую в качестве имени выполняемого процесса.

Пример:

Open3.popen2e('/usr/bin/date') { |i, o_and_e, t| o_and_e.gets }
# => "Thu Sep 28 01:58:45 PM CDT 2023\n"

Ruby вызывает исполняемый файл непосредственно, без оболочки и без расширения оболочки:

Open3.popen2e('doesnt_exist') { |i, o_and_e, t| o_and_e.gets } # Raises Errno::ENOENT

Если задано одно или несколько args, каждое из них является аргументом или параметром, передаваемым исполняемому файлу:

Open3.popen2e('echo', 'C #') { |i, o_and_e, t| o_and_e.gets }
# => "C #\n"
Open3.popen2e('echo', 'hello', 'world') { |i, o_and_e, t| o_and_e.gets }
# => "hello world\n"

Связанное:

  • Open3.popen2: Делает стандартный ввод и стандартный вывод дочернего процесса доступными как отдельные потоки, без доступа к потоку стандартной ошибки.

  • Open3.popen3: Делает стандартные потоки ввода, вывода и ошибки дочернего процесса доступными как отдельные потоки.

popen3([env, ] command_line, options = {}) → [stdin, stdout, stderr, wait_thread] Показать исходный код
popen3([env, ] exe_path, *args, options = {}) → [stdin, stdout, stderr, wait_thread]
popen3([env, ] command_line, options = {}) {|stdin, stdout, stderr, wait_thread| ... } → object
popen3([env, ] exe_path, *args, options = {}) {|stdin, stdout, stderr, wait_thread| ... } → object
# File lib/open3.rb, line 218
def popen3(*cmd, &block)
  if Hash === cmd.last
    opts = cmd.pop.dup
  else
    opts = {}
  end

  in_r, in_w = IO.pipe
  opts[:in] = in_r
  in_w.sync = true

  out_r, out_w = IO.pipe
  opts[:out] = out_w

  err_r, err_w = IO.pipe
  opts[:err] = err_w

  popen_run(cmd, opts, [in_r, out_w, err_w], [in_w, out_r, err_r], &block)
end

В основном это обёртка для Process.spawn, которая:

  • Создаёт дочерний процесс, вызывая Process.spawn с указанными аргументами.

  • Создаёт потоки stdin, stdout, и stderr, которые являются стандартными потоками ввода, вывода и ошибок дочернего процесса.

  • Создаёт поток wait_thread , который ждёт завершения дочернего процесса; у потока есть метод pid, который возвращает идентификатор процесса дочернего процесса.

Без блока возвращает массив [stdin, stdout, stderr, wait_thread]. Вызывающий код должен закрыть каждый из трёх возвращённых потоков.

stdin, stdout, stderr, wait_thread = Open3.popen3('echo')
# => [#<IO:fd 8>, #<IO:fd 10>, #<IO:fd 12>, #<Process::Waiter:0x00007f58d5428f58 run>]
stdin.close
stdout.close
stderr.close
wait_thread.pid   # => 2210481
wait_thread.value # => #<Process::Status: pid 2210481 exit 0>

При указании блока вызывает блок с четырьмя переменными (тремя потоками и потоком ожидания) и возвращает значение, возвращённое блоком. Вызывающему коду не нужно закрывать потоки:

Open3.popen3('echo') do |stdin, stdout, stderr, wait_thread|
  p stdin
  p stdout
  p stderr
  p wait_thread
  p wait_thread.pid
  p wait_thread.value
end

Вывод:

#<IO:fd 6>
#<IO:fd 7>
#<IO:fd 9>
#<Process::Waiter:0x00007f58d53606e8 sleep>
2211047
#<Process::Status: pid 2211047 exit 0>

Как и Process.spawn, этот метод имеет потенциальные уязвимости в области безопасности, если используется с непроверенным вводом; см. Ввод команд.

В отличие от Process.spawn, этот метод ожидает завершения дочернего процесса перед возвратом, поэтому вызывающий код не обязан делать это.

Если первым аргументом является хэш, он становится ведущим аргументом env в вызове Process.spawn; см. Выполнение окружения.

Если последним аргументом является хэш, он становится хвостовым аргументом options в вызове Process.spawn; см. Параметры выполнения.

Единственный обязательный аргумент — один из следующих:

  • command_line если это строка, и если она начинается с зарезервированного слова оболочки или специального встроенного, или если она содержит один или несколько метасимволов.

  • exe_path в противном случае.

Аргумент command_line

Строковый аргумент command_line представляет собой командную строку, которая передаётся оболочке; она должна начинаться с зарезервированного слова оболочки, начинаться со специального встроенного или содержать метасимволы:

Open3.popen3('if true; then echo "Foo"; fi') {|*args| p args } # Shell reserved word.
Open3.popen3('echo') {|*args| p args }                         # Built-in.
Open3.popen3('date > date.tmp') {|*args| p args }              # Contains meta character.

Вывод (аналогично для каждого вызова выше):

[#<IO:(closed)>, #<IO:(closed)>, #<IO:(closed)>, #<Process::Waiter:0x00007f58d52f28c8 dead>]

Командная строка также может содержать аргументы и параметры для команды:

Open3.popen3('echo "Foo"') { |i, o, e, t| o.gets }
"Foo\n"

Аргумент exe_path

Аргумент exe_path может быть одним из следующих:

  • Путь к исполняемому файлу, который нужно вызвать.

  • Массив из двух элементов, содержащий путь к исполняемому файлу и строку, используемую в качестве имени выполняемого процесса.

Пример:

Open3.popen3('/usr/bin/date') { |i, o, e, t| o.gets }
# => "Wed Sep 27 02:56:44 PM CDT 2023\n"

Ruby вызывает исполняемый файл напрямую, без оболочки и без расширения оболочки:

Open3.popen3('doesnt_exist') { |i, o, e, t| o.gets } # Raises Errno::ENOENT

Если указан один или несколько args, каждый из них представляет собой аргумент или параметр, который передаётся исполняемому файлу:

Open3.popen3('echo', 'C #') { |i, o, e, t| o.gets }
# => "C #\n"
Open3.popen3('echo', 'hello', 'world') { |i, o, e, t| o.gets }
# => "hello world\n"

Будьте внимательны, чтобы избежать тупиков. Потоки вывода stdout и stderr имеют буферы фиксированного размера, поэтому чрезмерное чтение из одного, но не из другого, может привести к тупику, когда заполнится нечитанный буфер. Чтобы избежать этого, stdout и stderr должны читаться одновременно (с помощью потоков или IO.select).

Связанные:

  • Open3.popen2: Делает потоки стандартного ввода и стандартного вывода дочернего процесса доступными как отдельные потоки без доступа к потоку стандартной ошибки.

  • Open3.popen2e: Делает потоки стандартного ввода и объединённого потока стандартного вывода и стандартной ошибки дочернего процесса доступными как отдельные потоки.

Методы закрытого экземпляра

capture2([env, ] command_line, options = {}) → [stdout_s, status] Показать исходный код
capture2([env, ] exe_path, *args, options = {}) → [stdout_s, status]
# File lib/open3.rb, line 775
def capture2(*cmd)
  if Hash === cmd.last
    opts = cmd.pop.dup
  else
    opts = {}
  end

  stdin_data = opts.delete(:stdin_data)
  binmode = opts.delete(:binmode)

  popen2(*cmd, opts) {|i, o, t|
    if binmode
      i.binmode
      o.binmode
    end
    out_reader = Thread.new { o.read }
    if stdin_data
      begin
        if stdin_data.respond_to? :readpartial
          IO.copy_stream(stdin_data, i)
        else
          i.write stdin_data
        end
      rescue Errno::EPIPE
      end
    end
    i.close
    [out_reader.value, t.value]
  }
end

В основном это обертка для Open3.popen3, которая:

  • Создаёт дочерний процесс, вызывая Open3.popen3 с заданными аргументами (кроме определённых записей в хеше options; см. ниже).

  • Возвращает строку stdout_s стандартного вывода дочернего процесса.

  • Возвращает status объект Process::Status, представляющий код завершения дочернего процесса.

Возвращает массив [stdout_s, status]:

stdout_s, status = Open3.capture2('echo "Foo"')
# => ["Foo\n", #<Process::Status: pid 2326047 exit 0>]

Как и метод Process.spawn, этот метод имеет потенциальные уязвимости в области безопасности, если вызывается с недоверенными данными; см. Ввод команд.

В отличие от Process.spawn, этот метод ожидает завершения дочернего процесса перед возвратом, поэтому вызывающей стороне не нужно этого делать.

Если первый аргумент является хешем, он становится ведущим аргументом env в вызове Open3.popen3; см. Выполнение окружения.

Если последний аргумент является хешем, он становится заключительным аргументом options в вызове Open3.popen3; см. Параметры выполнения.

Хеш options задан; две опции действуют локально в методе Open3.capture2:

  • Если запись options[:stdin_data] существует, запись удаляется, а её строковое значение отправляется в стандартный ввод команды:

    Open3.capture2('tee', stdin_data: 'Foo')
    
    # => ["Foo", #<Process::Status: pid 2326087 exit 0>]
    
  • Если запись options[:binmode] существует, запись удаляется, и внутренние потоки устанавливаются в двоичный режим.

Единственный необходимый аргумент — один из следующих:

  • command_line если это строка, и если она начинается со служебного слова оболочки или специального встроенного, или если она содержит один или несколько метасимволов.

  • exe_path в противном случае.

Аргумент command_line

Строковый аргумент command_line — это командная строка, которая будет передана оболочке; она должна начинаться со служебного слова оболочки, начинаться со специального встроенного или содержать метасимволы:

Open3.capture2('if true; then echo "Foo"; fi') # Shell reserved word.
# => ["Foo\n", #<Process::Status: pid 2326131 exit 0>]
Open3.capture2('echo')                         # Built-in.
# => ["\n", #<Process::Status: pid 2326139 exit 0>]
Open3.capture2('date > date.tmp')              # Contains meta character.
# => ["", #<Process::Status: pid 2326174 exit 0>]

Командная строка также может содержать аргументы и параметры для команды:

Open3.capture2('echo "Foo"')
# => ["Foo\n", #<Process::Status: pid 2326183 exit 0>]

Аргумент exe_path

Аргумент exe_path — это один из следующих вариантов:

  • Путь к исполняемому файлу, который должен быть вызван.

  • Массив из 2 элементов, содержащий путь к исполняемому файлу и строку, которая должна использоваться в качестве имени выполняемого процесса.

Пример:

Open3.capture2('/usr/bin/date')
# => ["Fri Sep 29 01:00:39 PM CDT 2023\n", #<Process::Status: pid 2326222 exit 0>]

Ruby вызывает исполняемый файл напрямую, без оболочки и без расширения оболочки:

Open3.capture2('doesnt_exist') # Raises Errno::ENOENT

Если указано один или несколько args, каждый из них является аргументом или параметром, который должен быть передан исполняемому файлу:

Open3.capture2('echo', 'C #')
# => ["C #\n", #<Process::Status: pid 2326267 exit 0>]
Open3.capture2('echo', 'hello', 'world')
# => ["hello world\n", #<Process::Status: pid 2326299 exit 0>]
capture2e([env, ] command_line, options = {}) → [stdout_and_stderr_s, status] Показать исходный код
capture2e([env, ] exe_path, *args, options = {}) → [stdout_and_stderr_s, status]
# File lib/open3.rb, line 902
def capture2e(*cmd)
  if Hash === cmd.last
    opts = cmd.pop.dup
  else
    opts = {}
  end

  stdin_data = opts.delete(:stdin_data)
  binmode = opts.delete(:binmode)

  popen2e(*cmd, opts) {|i, oe, t|
    if binmode
      i.binmode
      oe.binmode
    end
    outerr_reader = Thread.new { oe.read }
    if stdin_data
      begin
        if stdin_data.respond_to? :readpartial
          IO.copy_stream(stdin_data, i)
        else
          i.write stdin_data
        end
      rescue Errno::EPIPE
      end
    end
    i.close
    [outerr_reader.value, t.value]
  }
end

В основном это обертка для Open3.popen3, которая:

  • Создаёт дочерний процесс, вызывая Open3.popen3 с заданными аргументами (кроме определённых записей в хеше options; см. ниже).

  • Возвращает строку stdout_and_stderr_s объединённого стандартного вывода и стандартной ошибки дочернего процесса.

  • Возвращает status объект Process::Status, представляющий код завершения дочернего процесса.

Возвращает массив [stdout_and_stderr_s, status]:

stdout_and_stderr_s, status = Open3.capture2e('echo "Foo"')
# => ["Foo\n", #<Process::Status: pid 2371692 exit 0>]

Как и метод Process.spawn, этот метод имеет потенциальные уязвимости в области безопасности, если вызывается с недоверенными данными; см. Ввод команд.

В отличие от Process.spawn, этот метод ожидает завершения дочернего процесса перед возвратом, поэтому вызывающей стороне не нужно этого делать.

Если первый аргумент является хешем, он становится ведущим аргументом env в вызове Open3.popen3; см. Выполнение окружения.

Если последний аргумент является хешем, он становится заключительным аргументом options в вызове Open3.popen3; см. Параметры выполнения.

Хеш options задан; две опции действуют локально в методе Open3.capture2e:

  • Если запись options[:stdin_data] существует, запись удаляется, а её строковое значение отправляется в стандартный ввод команды:

    Open3.capture2e('tee', stdin_data: 'Foo')
    # => ["Foo", #<Process::Status: pid 2371732 exit 0>]
    
  • Если запись options[:binmode] существует, запись удаляется, и внутренние потоки устанавливаются в двоичный режим.

Единственный необходимый аргумент — один из следующих:

  • command_line если это строка, и если она начинается со служебного слова оболочки или специального встроенного, или если она содержит один или несколько метасимволов.

  • exe_path в противном случае.

Аргумент command_line

Строковый аргумент command_line — это командная строка, которая будет передана оболочке; она должна начинаться со служебного слова оболочки, начинаться со специального встроенного или содержать метасимволы:

Open3.capture2e('if true; then echo "Foo"; fi') # Shell reserved word.
# => ["Foo\n", #<Process::Status: pid 2371740 exit 0>]
Open3.capture2e('echo')                         # Built-in.
# => ["\n", #<Process::Status: pid 2371774 exit 0>]
Open3.capture2e('date > date.tmp')              # Contains meta character.
# => ["", #<Process::Status: pid 2371812 exit 0>]

Командная строка также может содержать аргументы и параметры для команды:

Open3.capture2e('echo "Foo"')
# => ["Foo\n", #<Process::Status: pid 2326183 exit 0>]

Аргумент exe_path

Аргумент exe_path — это один из следующих вариантов:

  • Путь к исполняемому файлу, который должен быть вызван.

  • Массив из 2 элементов, содержащий путь к исполняемому файлу и строку, которая должна использоваться в качестве имени выполняемого процесса.

Пример:

Open3.capture2e('/usr/bin/date')
# => ["Sat Sep 30 09:01:46 AM CDT 2023\n", #<Process::Status: pid 2371820 exit 0>]

Ruby вызывает исполняемый файл напрямую, без оболочки и без расширения оболочки:

Open3.capture2e('doesnt_exist') # Raises Errno::ENOENT

Если указано один или несколько args, каждый из них является аргументом или параметром, который должен быть передан исполняемому файлу:

Open3.capture2e('echo', 'C #')
# => ["C #\n", #<Process::Status: pid 2371856 exit 0>]
Open3.capture2e('echo', 'hello', 'world')
# => ["hello world\n", #<Process::Status: pid 2371894 exit 0>]
capture3([env, ] command_line, options = {}) → [stdout_s, stderr_s, status] Показать исходный код
capture3([env, ] exe_path, *args, options = {}) → [stdout_s, stderr_s, status]
# File lib/open3.rb, line 648
def capture3(*cmd)
  if Hash === cmd.last
    opts = cmd.pop.dup
  else
    opts = {}
  end

  stdin_data = opts.delete(:stdin_data) || ''
  binmode = opts.delete(:binmode)

  popen3(*cmd, opts) {|i, o, e, t|
    if binmode
      i.binmode
      o.binmode
      e.binmode
    end
    out_reader = Thread.new { o.read }
    err_reader = Thread.new { e.read }
    begin
      if stdin_data.respond_to? :readpartial
        IO.copy_stream(stdin_data, i)
      else
        i.write stdin_data
      end
    rescue Errno::EPIPE
    end
    i.close
    [out_reader.value, err_reader.value, t.value]
  }
end

В основном это обёртка для Open3.popen3, которая:

  • Создаёт дочерний процесс, вызывая Open3.popen3 с заданными аргументами (кроме определённых записей в хэше options; см. ниже).

  • Возвращает в виде строк stdout_s и stderr_s стандартный вывод и стандартную ошибку дочернего процесса.

  • Возвращает в виде status объект Process::Status, представляющий код завершения дочернего процесса.

Возвращает массив [stdout_s, stderr_s, status]:

stdout_s, stderr_s, status = Open3.capture3('echo "Foo"')
# => ["Foo\n", "", #<Process::Status: pid 2281954 exit 0>]

Как и метод Process.spawn, этот метод имеет потенциальные уязвимости безопасности, если вызывается с недоверенными данными; см. Ввод команд.

В отличие от Process.spawn, этот метод ожидает завершения дочернего процесса перед возвратом, поэтому вызывающей стороне не нужно этого делать.

Если первый аргумент является хэшем, он становится ведущим аргументом env в вызове Open3.popen3; см. Окружение выполнения.

Если последний аргумент является хэшем, он становится конечным аргументом options в вызове Open3.popen3; см. Параметры выполнения.

Хэш options задаётся; два параметра имеют локальное действие в методе Open3.capture3:

  • Если запись options[:stdin_data] существует, она удаляется, а её строковое значение передаётся на стандартный ввод команды:

    Open3.capture3('tee', stdin_data: 'Foo')
    # => ["Foo", "", #<Process::Status: pid 2319575 exit 0>]
    
  • Если запись options[:binmode] существует, она удаляется, и внутренние потоки устанавливаются в двоичный режим.

Единственный обязательный аргумент — один из следующих:

  • command_line если это строка, и если она начинается с зарезервированного слова оболочки или специального встроенного элемента, или если она содержит один или несколько метасимволов.

  • exe_path в противном случае.

Аргумент command_line

Строковый аргумент command_line — это командная строка, передаваемая оболочке; она должна начинаться с зарезервированного слова оболочки, специального встроенного элемента или содержать метасимволы:

Open3.capture3('if true; then echo "Foo"; fi') # Shell reserved word.
# => ["Foo\n", "", #<Process::Status: pid 2282025 exit 0>]
Open3.capture3('echo')                         # Built-in.
# => ["\n", "", #<Process::Status: pid 2282092 exit 0>]
Open3.capture3('date > date.tmp')              # Contains meta character.
# => ["", "", #<Process::Status: pid 2282110 exit 0>]

Командная строка также может содержать аргументы и параметры для команды:

Open3.capture3('echo "Foo"')
# => ["Foo\n", "", #<Process::Status: pid 2282092 exit 0>]

Аргумент exe_path

Аргумент exe_path — это один из следующих:

  • Путь к исполняемому файлу, который будет вызван.

  • Массив из 2 элементов, содержащий путь к исполняемому файлу и строку, используемую в качестве имени выполняемого процесса.

Пример:

Open3.capture3('/usr/bin/date')
# => ["Thu Sep 28 05:03:51 PM CDT 2023\n", "", #<Process::Status: pid 2282300 exit 0>]

Ruby вызывает исполняемый файл напрямую без оболочки и без расширения оболочки:

Open3.capture3('doesnt_exist') # Raises Errno::ENOENT

Если указано один или несколько args каждый из них является аргументом или параметром, передаваемым исполняемому файлу:

Open3.capture3('echo', 'C #')
# => ["C #\n", "", #<Process::Status: pid 2282368 exit 0>]
Open3.capture3('echo', 'hello', 'world')
# => ["hello world\n", "", #<Process::Status: pid 2282372 exit 0>]
pipeline([env, ] *cmds, options = {}) → array_of_statuses Показать исходный код
# File lib/open3.rb, line 1334
def pipeline(*cmds)
  if Hash === cmds.last
    opts = cmds.pop.dup
  else
    opts = {}
  end

  pipeline_run(cmds, opts, [], []) {|ts|
    ts.map(&:value)
  }
end

В основном это обёртка для Process.spawn, которая:

  • Создаёт дочерний процесс для каждого из указанных cmds с помощью вызова Process.spawn.

  • Перенаправляет stdout от каждого дочернего процесса к stdin следующего дочернего процесса или, в случае последнего дочернего процесса, к stdout вызывающей стороны.

  • Ожидает завершения дочерних процессов.

  • Возвращает массив объектов Process::Status (по одному для каждого дочернего процесса).

Пример:

wait_threads = Open3.pipeline('ls', 'grep R')
# => [#<Process::Status: pid 2139200 exit 0>, #<Process::Status: pid 2139202 exit 0>]

Вывод:

Rakefile
README.md

Как и Process.spawn, этот метод имеет потенциальные уязвимости безопасности, если вызывается с недоверенными данными; см. Ввод команд.

Если первый аргумент — хэш, он становится ведущим аргументом env в каждом вызове Process.spawn; см. Окружение выполнения.

Если последний аргумент — хэш, он становится конечным аргументом options в каждом вызове Process.spawn‘ см. Параметры выполнения.

Каждый оставшийся аргумент в cmds — это один из:

  • A command_line: строка, начинающаяся с зарезервированного слова оболочки или специального встроенного элемента, или содержащая один или несколько метасимволов.

  • An exe_path: строковый путь к вызываемому исполняемому файлу.

  • Массив, содержащий command_line или exe_path, а также ноль или более строковых аргументов для команды.

См. Аргумент command_line или exe_path.

pipeline_r([env, ] *cmds, options = {}) → [last_stdout, wait_threads] Показать исходный код
# File lib/open3.rb, line 1104
def pipeline_r(*cmds, &block)
  if Hash === cmds.last
    opts = cmds.pop.dup
  else
    opts = {}
  end

  out_r, out_w = IO.pipe
  opts[:out] = out_w

  pipeline_run(cmds, opts, [out_w], [out_r], &block)
end

В основном это обёртка для Process.spawn, которая:

  • Создаёт дочерний процесс для каждого из указанных cmds с помощью вызова Process.spawn.

  • Перенаправляет stdout от каждого дочернего процесса к stdin следующего дочернего процесса или, в случае последнего дочернего процесса, к stdout вызывающей стороны.

Метод не ожидает завершения дочерних процессов, поэтому вызывающая сторона должна это сделать.

Без блока возвращает массив из 2 элементов, содержащий:

  • Поток stdout последнего дочернего процесса.

  • Массив потоков ожидания всех дочерних процессов.

Пример:

last_stdout, wait_threads = Open3.pipeline_r('ls', 'grep R')
# => [#<IO:fd 5>, [#<Process::Waiter:0x000055e8de2f9898 dead>, #<Process::Waiter:0x000055e8de2f94b0 sleep>]]
puts last_stdout.read
wait_threads.each do |wait_thread|
  wait_thread.join
end

Вывод:

Rakefile
README.md

С заданным блоком вызывает блок с потоком stdout последнего дочернего процесса и массивом потоков ожидания:

Open3.pipeline_r('ls', 'grep R') do |last_stdout, wait_threads|
  puts last_stdout.read
  wait_threads.each do |wait_thread|
    wait_thread.join
  end
end

Вывод:

Rakefile
README.md

Как и Process.spawn, этот метод имеет потенциальные уязвимости безопасности, если вызывается с недоверенными данными; см. Ввод команд.

Если первый аргумент — хэш, он становится ведущим аргументом env в каждом вызове Process.spawn; см. Окружение выполнения.

Если последний аргумент — хэш, он становится конечным аргументом options в каждом вызове Process.spawn; см. Параметры выполнения.

Каждый оставшийся аргумент в cmds — это один из:

  • A command_line: строка, начинающаяся с зарезервированного слова оболочки или специального встроенного элемента, или содержащая один или несколько метасимволов.

  • An exe_path: строковый путь к вызываемому исполняемому файлу.

  • Массив, содержащий command_line или exe_path, а также ноль или более строковых аргументов для команды.

См. Аргумент command_line или exe_path.

pipeline_rw([env, ] *cmds, options = {}) → [first_stdin, last_stdout, wait_threads] Показать исходный код
# File lib/open3.rb, line 1014
def pipeline_rw(*cmds, &block)
  if Hash === cmds.last
    opts = cmds.pop.dup
  else
    opts = {}
  end

  in_r, in_w = IO.pipe
  opts[:in] = in_r
  in_w.sync = true

  out_r, out_w = IO.pipe
  opts[:out] = out_w

  pipeline_run(cmds, opts, [in_r, out_w], [in_w, out_r], &block)
end

В основном это обёртка для Process.spawn, которая:

  • Создаёт дочерний процесс для каждого из переданных cmds, вызывая Process.spawn.

  • Перенаправляет stdout от каждого дочернего процесса к stdin следующего дочернего процесса, или, для первого дочернего процесса, от входного потока вызывающего процесса, или, для последнего дочернего процесса, во входной поток вызывающего процесса.

Метод не ожидает завершения дочерних процессов, поэтому вызывающий процесс должен сделать это самостоятельно.

Без блока возвращает массив из 3 элементов, содержащий:

  • Поток stdin первого дочернего процесса.

  • Поток stdout последнего дочернего процесса.

  • Массив потоков ожидания для всех дочерних процессов.

Пример:

first_stdin, last_stdout, wait_threads = Open3.pipeline_rw('sort', 'cat -n')
# => [#<IO:fd 20>, #<IO:fd 21>, [#<Process::Waiter:0x000055e8de29ab40 sleep>, #<Process::Waiter:0x000055e8de29a690 sleep>]]
first_stdin.puts("foo\nbar\nbaz")
first_stdin.close # Send EOF to sort.
puts last_stdout.read
wait_threads.each do |wait_thread|
  wait_thread.join
end

Вывод:

1 bar
2 baz
3 foo

При наличии блока вызывает блок с потоком stdin первого дочернего процесса, потоком stdout последнего дочернего процесса и массивом потоков ожидания:

Open3.pipeline_rw('sort', 'cat -n') do |first_stdin, last_stdout, wait_threads|
  first_stdin.puts "foo\nbar\nbaz"
  first_stdin.close # send EOF to sort.
  puts last_stdout.read
  wait_threads.each do |wait_thread|
    wait_thread.join
  end
end

Вывод:

1 bar
2 baz
3 foo

Как и Process.spawn, этот метод имеет потенциальные уязвимости безопасности при использовании недоверенного ввода; см. Command Injection.

Если первый аргумент является хэшем, он становится ведущим аргументом env в каждом вызове Process.spawn; см. Execution Environment.

Если последний аргумент является хэшем, он становится хвостовым аргументом options в каждом вызове Process.spawn; см. Execution Options.

Каждый последующий аргумент в cmds является одним из:

  • command_line: строка, начинающаяся с зарезервированного слова оболочки или специального встроенного, или содержащая один или несколько метасимволов.

  • exe_path: строковой путь к исполняемому файлу, который будет вызван.

  • Массив, содержащий command_line или exe_path, а также ноль или более строковых аргументов для команды.

См. Argument command_line or exe_path.

pipeline_start([env, ] *cmds, options = {}) → [wait_threads] Показать исходный код
# File lib/open3.rb, line 1272
def pipeline_start(*cmds, &block)
  if Hash === cmds.last
    opts = cmds.pop.dup
  else
    opts = {}
  end

  if block
    pipeline_run(cmds, opts, [], [], &block)
  else
    ts, = pipeline_run(cmds, opts, [], [])
    ts
  end
end

В основном это обёртка для Process.spawn, которая:

  • Создаёт дочерний процесс для каждого из переданных cmds при вызове Process.spawn.

  • Не ожидает завершения дочерних процессов.

Без блока возвращает массив потоков ожидания для всех дочерних процессов.

Пример:

wait_threads = Open3.pipeline_start('ls', 'grep R')
# => [#<Process::Waiter:0x000055e8de9d2bb0 run>, #<Process::Waiter:0x000055e8de9d2890 run>]
wait_threads.each do |wait_thread|
  wait_thread.join
end

Вывод:

Rakefile
README.md

При наличии блока вызывает блок с массивом потоков ожидания:

Open3.pipeline_start('ls', 'grep R') do |wait_threads|
  wait_threads.each do |wait_thread|
    wait_thread.join
  end
end

Вывод:

Rakefile
README.md

Как и Process.spawn, этот метод имеет потенциальные уязвимости безопасности при использовании недоверенного ввода; см. Command Injection.

Если первый аргумент является хэшем, он становится ведущим аргументом env в каждом вызове Process.spawn; см. Execution Environment.

Если последний аргумент является хэшем, он становится хвостовым аргументом options в каждом вызове Process.spawn; см. Execution Options.

Каждый последующий аргумент в cmds является одним из:

  • command_line: строка, начинающаяся с зарезервированного слова оболочки или специального встроенного, или содержащая один или несколько метасимволов.

  • exe_path: строковой путь к исполняемому файлу, который будет вызван.

  • Массив, содержащий command_line или exe_path, а также ноль или более строковых аргументов для команды.

См. Argument command_line or exe_path.

pipeline_w([env, ] *cmds, options = {}) → [first_stdin, wait_threads] Показать исходный код
# File lib/open3.rb, line 1195
def pipeline_w(*cmds, &block)
  if Hash === cmds.last
    opts = cmds.pop.dup
  else
    opts = {}
  end

  in_r, in_w = IO.pipe
  opts[:in] = in_r
  in_w.sync = true

  pipeline_run(cmds, opts, [in_r], [in_w], &block)
end

В основном это обёртка для Process.spawn, которая:

  • Создаёт дочерний процесс для каждого из переданных cmds при вызове Process.spawn.

  • Перенаправляет stdout от каждого дочернего процесса к stdin следующего дочернего процесса, или, для первого дочернего процесса, перенаправляет входной поток вызывающего процесса в стандартный ввод дочернего процесса.

Метод не ожидает завершения дочерних процессов, поэтому вызывающий процесс должен сделать это самостоятельно.

Без блока возвращает массив из 2 элементов, содержащий:

  • Поток stdin первого дочернего процесса.

  • Массив потоков ожидания для всех дочерних процессов.

Пример:

first_stdin, wait_threads = Open3.pipeline_w('sort', 'cat -n')
# => [#<IO:fd 7>, [#<Process::Waiter:0x000055e8de928278 run>, #<Process::Waiter:0x000055e8de923e80 run>]]
first_stdin.puts("foo\nbar\nbaz")
first_stdin.close # Send EOF to sort.
wait_threads.each do |wait_thread|
  wait_thread.join
end

Вывод:

1 bar
2 baz
3 foo

При наличии блока вызывает блок с потоком stdin первого дочернего процесса и массивом потоков ожидания:

Open3.pipeline_w('sort', 'cat -n') do |first_stdin, wait_threads|
  first_stdin.puts("foo\nbar\nbaz")
  first_stdin.close # Send EOF to sort.
  wait_threads.each do |wait_thread|
    wait_thread.join
  end
end

Вывод:

1 bar
2 baz
3 foo

Как и Process.spawn, этот метод имеет потенциальные уязвимости безопасности при использовании недоверенного ввода; см. Command Injection.

Если первый аргумент является хэшем, он становится ведущим аргументом env в каждом вызове Process.spawn; см. Execution Environment.

Если последний аргумент является хэшем, он становится хвостовым аргументом options в каждом вызове Process.spawn; см. Execution Options.

Каждый последующий аргумент в cmds является одним из:

  • command_line: строка, начинающаяся с зарезервированного слова оболочки или специального встроенного, или содержащая один или несколько метасимволов.

  • exe_path: строковой путь к исполняемому файлу, который будет вызван.

  • Массив, содержащий command_line или exe_path, а также ноль или более строковых аргументов для команды.

См. Argument command_line or exe_path.

popen2([env, ] command_line, options = {}) → [stdin, stdout, wait_thread] Показать исходный код
popen2([env, ] exe_path, *args, options = {}) → [stdin, stdout, wait_thread]
popen2([env, ] command_line, options = {}) {|stdin, stdout, wait_thread| ... } → object
popen2([env, ] exe_path, *args, options = {}) {|stdin, stdout, wait_thread| ... } → object
# File lib/open3.rb, line 365
def popen2(*cmd, &block)
  if Hash === cmd.last
    opts = cmd.pop.dup
  else
    opts = {}
  end

  in_r, in_w = IO.pipe
  opts[:in] = in_r
  in_w.sync = true

  out_r, out_w = IO.pipe
  opts[:out] = out_w

  popen_run(cmd, opts, [in_r, out_w], [in_w, out_r], &block)
end

В основном это обёртка для Process.spawn, которая:

  • Создаёт дочерний процесс, вызывая Process.spawn с заданными аргументами.

  • Создаёт потоки stdin и stdout, которые являются стандартными потоками ввода и вывода в дочернем процессе.

  • Создаёт поток wait_thread, который ждёт завершения дочернего процесса; у потока есть метод pid, возвращающий идентификатор процесса дочернего процесса.

Без блока возвращает массив [stdin, stdout, wait_thread]. Вызывающий код должен закрыть каждый из двух возвращённых потоков.

stdin, stdout, wait_thread = Open3.popen2('echo')
# => [#<IO:fd 6>, #<IO:fd 7>, #<Process::Waiter:0x00007f58d52dbe98 run>]
stdin.close
stdout.close
wait_thread.pid   # => 2263572
wait_thread.value # => #<Process::Status: pid 2263572 exit 0>

С блоком вызывает блок с тремя переменными (два потока и поток ожидания) и возвращает значение блока. Вызывающему коду не нужно закрывать потоки:

Open3.popen2('echo') do |stdin, stdout, wait_thread|
  p stdin
  p stdout
  p wait_thread
  p wait_thread.pid
  p wait_thread.value
end

Вывод:

#<IO:fd 6>
#<IO:fd 7>
#<Process::Waiter:0x00007f58d59a34b0 sleep>
2263636
#<Process::Status: pid 2263636 exit 0>

Как и Process.spawn, этот метод имеет потенциальные уязвимости в области безопасности, если вызван с недоверенным вводом; см. Ввод команд.

В отличие от Process.spawn, этот метод ждёт завершения дочернего процесса перед возвратом, поэтому вызывающий код не должен этого делать.

Если первый аргумент является хешем, он становится ведущим аргументом env в вызове Process.spawn; см. Окружение выполнения.

Если последний аргумент является хешем, он становится заключительным аргументом options в вызове Process.spawn; см. Параметры выполнения.

Единственный обязательный аргумент — один из следующих:

  • command_line если это строка, если она начинается с зарезервированного слова оболочки или специального встроенного элемента, или если она содержит один или несколько метасимволов.

  • exe_path в противном случае.

Аргумент command_line

Строковый аргумент command_line — это командная строка, передаваемая оболочке; она должна начинаться с зарезервированного слова оболочки, с особым встроенным элементом или содержать метасимволы:

Open3.popen2('if true; then echo "Foo"; fi') {|*args| p args } # Shell reserved word.
Open3.popen2('echo') {|*args| p args }                         # Built-in.
Open3.popen2('date > date.tmp') {|*args| p args }              # Contains meta character.

Вывод (аналогично для каждого вызова выше):

# => [#<IO:(closed)>, #<IO:(closed)>, #<Process::Waiter:0x00007f7577dfe410 dead>]

Командная строка может также содержать аргументы и параметры для команды:

Open3.popen2('echo "Foo"') { |i, o, t| o.gets }
"Foo\n"

Аргумент exe_path

Аргумент exe_path может быть одним из следующих:

  • Путь к исполняемому файлу, который необходимо вызвать.

  • Массив из двух элементов, содержащий путь к исполняемому файлу и строку, используемую в качестве имени выполняемого процесса.

Пример:

Open3.popen2('/usr/bin/date') { |i, o, t| o.gets }
# => "Thu Sep 28 09:41:06 AM CDT 2023\n"

Ruby вызывает исполняемый файл напрямую без оболочки и без расширения оболочки:

Open3.popen2('doesnt_exist') { |i, o, t| o.gets } # Raises Errno::ENOENT

Если задан один или несколько args, каждый из них — аргумент или параметр, передаваемый исполняемому файлу:

Open3.popen2('echo', 'C #') { |i, o, t| o.gets }
# => "C #\n"
Open3.popen2('echo', 'hello', 'world') { |i, o, t| o.gets }
# => "hello world\n"

Связанное:

  • Open3.popen2e: Делает стандартный ввод и объединение стандартного вывода и стандартной ошибки дочернего процесса доступными как отдельные потоки.

  • Open3.popen3: Делает стандартные потоки ввода, вывода и ошибки дочернего процесса доступными как отдельные потоки.

popen2e([env, ] command_line, options = {}) → [stdin, stdout_and_stderr, wait_thread] Показать исходный код
popen2e([env, ] exe_path, *args, options = {}) → [stdin, stdout_and_stderr, wait_thread]
popen2e([env, ] command_line, options = {}) {|stdin, stdout_and_stderr, wait_thread| ... } → object
popen2e([env, ] exe_path, *args, options = {}) {|stdin, stdout_and_stderr, wait_thread| ... } → object
# File lib/open3.rb, line 508
def popen2e(*cmd, &block)
  if Hash === cmd.last
    opts = cmd.pop.dup
  else
    opts = {}
  end

  in_r, in_w = IO.pipe
  opts[:in] = in_r
  in_w.sync = true

  out_r, out_w = IO.pipe
  opts[[:out, :err]] = out_w

  popen_run(cmd, opts, [in_r, out_w], [in_w, out_r], &block)
ensure
  if block
    in_r.close
    in_w.close
    out_r.close
    out_w.close
  end
end

В основном это обёртка для Process.spawn, которая:

  • Создаёт дочерний процесс, вызывая Process.spawn с заданными аргументами.

  • Создаёт потоки stdin, stdout_and_stderr, которые являются стандартным потоком ввода и объединением стандартных потоков вывода и ошибки в дочернем процессе.

  • Создаёт поток wait_thread, который ждёт завершения дочернего процесса; у потока есть метод pid, возвращающий идентификатор процесса дочернего процесса.

Без блока возвращает массив [stdin, stdout_and_stderr, wait_thread]. Вызывающий код должен закрыть каждый из двух возвращённых потоков.

stdin, stdout_and_stderr, wait_thread = Open3.popen2e('echo')
# => [#<IO:fd 6>, #<IO:fd 7>, #<Process::Waiter:0x00007f7577da4398 run>]
stdin.close
stdout_and_stderr.close
wait_thread.pid   # => 2274600
wait_thread.value # => #<Process::Status: pid 2274600 exit 0>

С блоком вызывает блок с тремя переменными (два потока и поток ожидания) и возвращает значение блока. Вызывающему коду не нужно закрывать потоки:

Open3.popen2e('echo') do |stdin, stdout_and_stderr, wait_thread|
  p stdin
  p stdout_and_stderr
  p wait_thread
  p wait_thread.pid
  p wait_thread.value
end

Вывод:

#<IO:fd 6>
#<IO:fd 7>
#<Process::Waiter:0x00007f75777578c8 sleep>
2274763
#<Process::Status: pid 2274763 exit 0>

Как и Process.spawn, этот метод имеет потенциальные уязвимости в области безопасности, если вызван с недоверенным вводом; см. Ввод команд.

В отличие от Process.spawn, этот метод ждёт завершения дочернего процесса перед возвратом, поэтому вызывающий код не должен этого делать.

Если первый аргумент является хешем, он становится ведущим аргументом env в вызове Process.spawn; см. Окружение выполнения.

Если последний аргумент является хешем, он становится заключительным аргументом options в вызове Process.spawn; см. Параметры выполнения.

Единственный обязательный аргумент — один из следующих:

  • command_line если это строка, если она начинается с зарезервированного слова оболочки или специального встроенного элемента, или если она содержит один или несколько метасимволов.

  • exe_path в противном случае.

Аргумент command_line

Строковый аргумент command_line — это командная строка, передаваемая оболочке; она должна начинаться с зарезервированного слова оболочки, с особым встроенным элементом или содержать метасимволы:

Open3.popen2e('if true; then echo "Foo"; fi') {|*args| p args } # Shell reserved word.
Open3.popen2e('echo') {|*args| p args }                         # Built-in.
Open3.popen2e('date > date.tmp') {|*args| p args }              # Contains meta character.

Вывод (аналогично для каждого вызова выше):

# => [#<IO:(closed)>, #<IO:(closed)>, #<Process::Waiter:0x00007f7577d8a1f0 dead>]

Командная строка может также содержать аргументы и параметры для команды:

Open3.popen2e('echo "Foo"') { |i, o_and_e, t| o_and_e.gets }
"Foo\n"

Аргумент exe_path

Аргумент exe_path может быть одним из следующих:

  • Путь к исполняемому файлу, который необходимо вызвать.

  • Массив из двух элементов, содержащий путь к исполняемому файлу и строку, используемую в качестве имени выполняемого процесса.

Пример:

Open3.popen2e('/usr/bin/date') { |i, o_and_e, t| o_and_e.gets }
# => "Thu Sep 28 01:58:45 PM CDT 2023\n"

Ruby вызывает исполняемый файл напрямую без оболочки и без расширения оболочки:

Open3.popen2e('doesnt_exist') { |i, o_and_e, t| o_and_e.gets } # Raises Errno::ENOENT

Если задан один или несколько args, каждый из них — аргумент или параметр, передаваемый исполняемому файлу:

Open3.popen2e('echo', 'C #') { |i, o_and_e, t| o_and_e.gets }
# => "C #\n"
Open3.popen2e('echo', 'hello', 'world') { |i, o_and_e, t| o_and_e.gets }
# => "hello world\n"

Связанное:

  • Open3.popen2: Делает стандартные потоки ввода и вывода дочернего процесса доступными как отдельные потоки, без доступа к стандартному потоку ошибки.

  • Open3.popen3: Делает стандартные потоки ввода, вывода и ошибки дочернего процесса доступными как отдельные потоки.

popen3([env, ] command_line, options = {}) → [stdin, stdout, stderr, wait_thread] Показать исходный код
popen3([env, ] exe_path, *args, options = {}) → [stdin, stdout, stderr, wait_thread]
popen3([env, ] command_line, options = {}) {|stdin, stdout, stderr, wait_thread| ... } → object
popen3([env, ] exe_path, *args, options = {}) {|stdin, stdout, stderr, wait_thread| ... } → object
# File lib/open3.rb, line 218
def popen3(*cmd, &block)
  if Hash === cmd.last
    opts = cmd.pop.dup
  else
    opts = {}
  end

  in_r, in_w = IO.pipe
  opts[:in] = in_r
  in_w.sync = true

  out_r, out_w = IO.pipe
  opts[:out] = out_w

  err_r, err_w = IO.pipe
  opts[:err] = err_w

  popen_run(cmd, opts, [in_r, out_w, err_w], [in_w, out_r, err_r], &block)
end

В основном, это обёртка для Process.spawn, которая:

  • Создаёт дочерний процесс, вызывая Process.spawn с заданными аргументами.

  • Создаёт потоки stdin, stdout, и stderr, которые являются стандартными потоками ввода, вывода и ошибок дочернего процесса.

  • Создаёт поток wait_thread , который ждёт завершения дочернего процесса; у потока есть метод pid, который возвращает идентификатор процесса дочернего процесса.

Без блока возвращает массив [stdin, stdout, stderr, wait_thread]. Вызывающий код должен закрыть каждый из трёх возвращённых потоков.

stdin, stdout, stderr, wait_thread = Open3.popen3('echo')
# => [#<IO:fd 8>, #<IO:fd 10>, #<IO:fd 12>, #<Process::Waiter:0x00007f58d5428f58 run>]
stdin.close
stdout.close
stderr.close
wait_thread.pid   # => 2210481
wait_thread.value # => #<Process::Status: pid 2210481 exit 0>

С блоком, вызывает блок с четырьмя переменными (три потока и поток ожидания) и возвращает результат выполнения блока. Вызывающий код не должен закрывать потоки:

Open3.popen3('echo') do |stdin, stdout, stderr, wait_thread|
  p stdin
  p stdout
  p stderr
  p wait_thread
  p wait_thread.pid
  p wait_thread.value
end

Вывод:

#<IO:fd 6>
#<IO:fd 7>
#<IO:fd 9>
#<Process::Waiter:0x00007f58d53606e8 sleep>
2211047
#<Process::Status: pid 2211047 exit 0>

Как и Process.spawn, этот метод имеет потенциальные уязвимости в области безопасности, если используется с недоверенными данными; см. Внедрение команд.

В отличие от Process.spawn, этот метод ждёт завершения дочернего процесса перед возвращением, поэтому вызывающий код не должен делать этого.

Если первый аргумент — хеш, он становится ведущим аргументом env при вызове Process.spawn; см. Окружающая среда выполнения.

Если последний аргумент — хеш, он становится заключительным аргументом options при вызове Process.spawn; см. Параметры выполнения.

Единственный необходимый аргумент — один из следующих:

  • command_line если это строка, и если она начинается с зарезервированного слова оболочки или специального встроенного, или если она содержит один или несколько метасимволов.

  • exe_path в противном случае.

Аргумент command_line

Строковый аргумент command_line — это командная строка, которая передаётся оболочке; она должна начинаться с зарезервированного слова оболочки, начинаться со специального встроенного или содержать метасимволы:

Open3.popen3('if true; then echo "Foo"; fi') {|*args| p args } # Shell reserved word.
Open3.popen3('echo') {|*args| p args }                         # Built-in.
Open3.popen3('date > date.tmp') {|*args| p args }              # Contains meta character.

Вывод (аналогично для каждого из вышеупомянутых вызовов):

[#<IO:(closed)>, #<IO:(closed)>, #<IO:(closed)>, #<Process::Waiter:0x00007f58d52f28c8 dead>]

Командная строка может также содержать аргументы и параметры для команды:

Open3.popen3('echo "Foo"') { |i, o, e, t| o.gets }
"Foo\n"

Аргумент exe_path

Аргумент exe_path — один из следующих:

  • Путь к исполняемому файлу, который должен быть вызван.

  • Массив из 2 элементов, содержащий путь к исполняемому файлу и строку, которая будет использоваться в качестве имени выполняемого процесса.

Пример:

Open3.popen3('/usr/bin/date') { |i, o, e, t| o.gets }
# => "Wed Sep 27 02:56:44 PM CDT 2023\n"

Ruby вызывает исполняемый файл напрямую, без оболочки и без расширения оболочки:

Open3.popen3('doesnt_exist') { |i, o, e, t| o.gets } # Raises Errno::ENOENT

Если указано один или несколько args, каждый из них является аргументом или параметром, который должен быть передан исполняемому файлу:

Open3.popen3('echo', 'C #') { |i, o, e, t| o.gets }
# => "C #\n"
Open3.popen3('echo', 'hello', 'world') { |i, o, e, t| o.gets }
# => "hello world\n"

Следите за предотвращением тупиков. Потоки вывода stdout и stderr имеют буферы фиксированного размера, поэтому интенсивное чтение из одного, но не из другого, может привести к тупику, когда заполняется незачитанный буфер. Чтобы избежать этого, stdout и stderr следует читать одновременно (с использованием потоков или IO.select).

Связанное:

  • Open3.popen2: Делает стандартные потоки ввода и вывода дочернего процесса доступными как отдельные потоки, без доступа к потоку стандартных ошибок.

  • Open3.popen2e: Делает стандартный поток ввода и объединённый поток стандартного вывода и стандартной ошибки дочернего процесса доступными как отдельные потоки.

Ruby Core © 1993–2022 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API