Spec-Zone.ru › Ruby 4.0

модуль 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 должен быть одним из следующих:

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

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

Пример:

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 должен быть одним из следующих:

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

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

Пример:

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 должен быть одним из следующих:

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

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

Пример:

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: строковый путь к вызываемому исполняемому файлу.

  • Массив, содержащий 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 вызывающего кода.

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

Если блок не задан, возвращается массив из двух элементов, содержащий:

  • Поток 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: строковый путь к вызываемому исполняемому файлу.

  • Массив, содержащий 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 следующего дочернего процесса, а для первого дочернего процесса — из stdin вызывающего кода, а для последнего — в stdout вызывающего кода.

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

Если блок не задан, возвращается массив из трёх элементов, содержащий:

  • Поток 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 следующего дочернего процесса, а для первого дочернего процесса передаёт stdout вызывающего кода в stdin дочернего процесса.

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

Если блок не задан, возвращается массив из двух элементов, содержащий:

  • Поток 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 должен быть одним из следующих:

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

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

Пример:

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 должен быть одним из следующих:

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

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

Пример:

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 должен быть одним из следующих:

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

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

Пример:

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: строковый путь к вызываемому исполняемому файлу.

  • Массив, содержащий 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 вызывающего кода.

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

Если блок не задан, возвращается массив из двух элементов, содержащий:

  • Поток 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: строковый путь к вызываемому исполняемому файлу.

  • Массив, содержащий 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 следующего дочернего процесса; для первого дочернего процесса данные поступают из stdin вызывающего кода, а для последнего передаются в stdout вызывающего кода.

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

Если блок не задан, возвращается массив из трёх элементов, содержащий:

  • Поток 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 следующего дочернего процесса; для первого дочернего процесса поток stdout вызывающего кода передаётся в stdin дочернего процесса.

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

Если блок не задан, возвращается массив из двух элементов, содержащий:

  • Поток 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: Предоставляет стандартный ввод и объединённые потоки стандартного вывода и стандартной ошибки дочернего процесса в виде отдельных потоков.

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

Spec-Zone.ru

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