Когда использовать каждый метод запуска подпроцесса в Ruby
1. ``
The Backtick
- определено в ядре
1. а) %x{}
Percent X <альтернативный синтаксис для The Backtick
- определено в parse.y, смотрите обсуждение
2. system()
3. fork()
4. open()
- открыть трубу
- Kernel# открыт
4.a. IO.popen()
<ведет себя так же, как open()
- открыть трубу
- IO# POPEN
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 ответов
используйте обратные пометки, когда вы хотите легко зафиксировать выходные данные программы в переменной. Вы, вероятно, хотите использовать это только для коротких программ, потому что это заблокирует.
system
удобно в двух разных случаях:а. У вас есть долго работающая программа, и вы хотите, чтобы вывод печатался во время ее работы (например,
system("tar zxvf some_big_tarball.tar.gz")
)б.
system
может обойти расширение оболочки, какexec
(сравните выводsystem "echo *"
а такжеsystem "echo", "*"
)системные блоки до выхода из подпроцесса.
fork
также есть несколько вариантов использования:а. Вы хотите запустить некоторый код ruby в отдельном процессе (например,
fork { .... }
б. Вы хотите запустить дочерний процесс (или другую программу), не блокируя прогресс вашего скрипта
fork { exec "bash" }
,fork
Ваш друг, если вы хотите демонизировать свою программу.IO.popen
полезно, когда вам нужно взаимодействовать со стандартным и стандартным входом в программу. Обратите внимание, что он не фиксирует стандартную ошибку, поэтому вам нужно перенаправить это с2>&1
если ты заботишься об этом.popen3
дает отдельный дескриптор файла для стандартной ошибки (для случая, когда вам нужно захватить это отдельно от стандартной ошибки)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 для регистрации незаинтересованности в их статусе; в противном случае операционная система может накапливать зомби-процессы.