Когда использовать каждый метод запуска подпроцесса в Ruby

1. `` The Backtick

1. а) %x{} Percent X <альтернативный синтаксис для The Backtick

2. system()

3. fork()

4. open()

4.a. IO.popen() <ведет себя так же, как open()

4.b. open("|-")

  • вилка в трубу

4.C. IO.popen("-") <ведет себя так же, как open("|-")

5. Open3.popen3()

  • require 'open3'
  • stdlib Open3

6. PTY.spawn()

  • require 'pty'
  • stdlib PTY

7. Shell.transact()

  • require 'shell'
  • stdlib Shell

Когда следует отказаться от верной галочки для одного из более сложных методов?

Редактировать 1. Большое спасибо Avdi за его посты, описывающие пример использования каждого метода: # 1 (& gist); № 2 (& gist); № 3

Это фантастические ресурсы для ответа на вопрос " Как", но они явно не составлены для того, чтобы отвечать, когда каждый из них должен использоваться или " Почему", и поэтому ИМХО не являются полными ответами на этот вопрос.

5 ответов

Решение
  1. используйте обратные пометки, когда вы хотите легко зафиксировать выходные данные программы в переменной. Вы, вероятно, хотите использовать это только для коротких программ, потому что это заблокирует.

  2. system удобно в двух разных случаях:

    а. У вас есть долго работающая программа, и вы хотите, чтобы вывод печатался во время ее работы (например, system("tar zxvf some_big_tarball.tar.gz"))

    б. system может обойти расширение оболочки, как exec (сравните вывод system "echo *" а также system "echo", "*")

    системные блоки до выхода из подпроцесса.

  3. fork также есть несколько вариантов использования:

    а. Вы хотите запустить некоторый код ruby ​​в отдельном процессе (например, fork { .... }

    б. Вы хотите запустить дочерний процесс (или другую программу), не блокируя прогресс вашего скрипта fork { exec "bash" },

    fork Ваш друг, если вы хотите демонизировать свою программу.

  4. IO.popen полезно, когда вам нужно взаимодействовать со стандартным и стандартным входом в программу. Обратите внимание, что он не фиксирует стандартную ошибку, поэтому вам нужно перенаправить это с 2>&1 если ты заботишься об этом.

  5. popen3 дает отдельный дескриптор файла для стандартной ошибки (для случая, когда вам нужно захватить это отдельно от стандартной ошибки)

  6. PTY.spawn необходимо, если вы хотите, чтобы порожденная программа работала так, как будто вы работаете с терминала. Увидеть разницу grep --color=auto pat file когда порожден system против PTY.spawn

Вот блок-схема, основанная на этом ответе. Смотрите также, используя script эмулировать терминал.

введите описание изображения здесь

В дополнение к приведенной выше блок-схеме /questions/23991763/kogda-ispolzovat-kazhdyij-metod-zapuska-podprotsessa-v-ruby/23991768#23991768, если кто-то хочет, чтобы она была редактируемой блок-схемой в уценке (на основе русалки ), вот она:

      ```mermaid
flowchart TD

A{{"Do I want to return to my ruby script, ever?"}} -- No --> B(["Use exec()"])
A -- Yes --> C{{"Is it OK to block until the process completes?"}}
C -- Yes --> D{{"Do I need the program's output to be returned?"}}
D -- Yes --> E(["Use backticks `` or %x{}"])
D -- No --> F(["Use system()"])
C -- No --> H{{"Do I need to interact with the output?"}}
H -- Yes --> J{{"Do I want STDERR?"}}
H -- No --> I(["Use fork()"])
J -- Yes --> L{{"Do I want STDERR in its own separate stream?"}}
J -- No --> K(["Use IO.popen()"])
L -- Yes --> M(["Use Open3.popen3()"])
L -- No --> N{{"Use PTY.spawn()"}}

O>"Outputs to STDOUT"] -.- F
P>"You can always emulate a terminal with the BSD utility called script"] -.- H
Q>"Separate child process; good for daemonizing"] -.- I
R>"You can still use 2>&1 to combine STDERR with STDOUT"] -.- K
S>"Emulates a terminal unconditionally"] -.- M

classDef decision fill:#f8fb99;
classDef action fill:#ffaead;
classDef note fill:#ddd,opacity:0.9,font-weight:200;

class A,C,D,H,J,L decision;
class B,E,F,I,K,M,N action;
class O,P,Q,R,S note;
```

Также есть Process.spawn. Из документов:

Этот метод похож на Kernel#system, но не ожидает завершения команды.

Родительский процесс должен использовать Process.wait для получения статуса завершения своего дочернего процесса или использовать Process.detach для регистрации незаинтересованности в их статусе; в противном случае операционная система может накапливать зомби-процессы.

Другие вопросы по тегам