модуль Open3
Open3 предоставляет доступ к stdin, stdout, stderr и потоку для ожидания завершения дочернего процесса при запуске другой программы. Вы можете указать различные атрибуты, перенаправления, текущую директорию и т.д. программы аналогично использованию Process.spawn.
-
#popen3 : каналы для stdin, stdout, stderr
-
#popen2 : каналы для stdin, stdout
-
#popen2e : каналы для stdin, объединённый stdout и stderr
-
#capture3 : передать строку для stdin; получить строки для stdout, stderr
-
#capture2 : передать строку для stdin; получить строку для stdout
-
#capture2e : передать строку для stdin; получить строку для объединённого stdout и stderr
-
#pipeline_rw : каналы для первого stdin и последнего stdout конвейера
-
#pipeline_r : канал для последнего stdout конвейера
-
#pipeline_w : канал для первого stdin конвейера
-
#pipeline_start : запустить конвейер без ожидания
-
#pipeline : запустить конвейер и дождаться его завершения
Методы публичного класса
# File lib/open3.rb, line 304
def capture2(*cmd, stdin_data: nil, binmode: false, **opts)
popen2(*cmd, opts) {|i, o, t|
if binmode
i.binmode
o.binmode
end
out_reader = Thread.new { o.read }
if stdin_data
begin
i.write stdin_data
rescue Errno::EPIPE
end
end
i.close
[out_reader.value, t.value]
}
end #capture2 захватывает стандартный вывод команды.
stdout_str, status = Open3.capture2([env,] cmd... [, opts])
Аргументы env, cmd и opts передаются в #popen3, за исключением opts[:stdin_data] и opts[:binmode]. См. Process.spawn.
Если указан opts[:stdin_data], он передаётся на стандартный ввод команды.
Если opts[:binmode] имеет значение true, внутренние каналы настроены на двоичный режим.
Пример:
# factor is a command for integer factorization.
o, s = Open3.capture2("factor", :stdin_data=>"42")
p o #=> "42: 2 3 7\n"
# generate x**2 graph in png using gnuplot.
gnuplot_commands = <<"End"
set terminal png
plot x**2, "-" with lines
1 14
2 1
3 8
4 5
e
End
image, s = Open3.capture2("gnuplot", :stdin_data=>gnuplot_commands, :binmode=>true)
# File lib/open3.rb, line 339
def capture2e(*cmd, stdin_data: nil, binmode: false, **opts)
popen2e(*cmd, opts) {|i, oe, t|
if binmode
i.binmode
oe.binmode
end
outerr_reader = Thread.new { oe.read }
if stdin_data
begin
i.write stdin_data
rescue Errno::EPIPE
end
end
i.close
[outerr_reader.value, t.value]
}
end #capture2e захватывает стандартный вывод и стандартную ошибку команды.
stdout_and_stderr_str, status = Open3.capture2e([env,] cmd... [, opts])
Аргументы env, cmd и opts передаются в #popen3, за исключением opts[:stdin_data] и opts[:binmode]. См. Process.spawn.
Если указан opts[:stdin_data], он передаётся на стандартный ввод команды.
Если opts[:binmode] имеет значение true, внутренние каналы настроены на двоичный режим.
Пример:
# capture make log
make_log, s = Open3.capture2e("make")
# File lib/open3.rb, line 256
def capture3(*cmd, stdin_data: '', binmode: false, **opts)
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
i.write stdin_data
rescue Errno::EPIPE
end
i.close
[out_reader.value, err_reader.value, t.value]
}
end #capture3 захватывает стандартный вывод и стандартную ошибку команды.
stdout_str, stderr_str, status = Open3.capture3([env,] cmd... [, opts])
Аргументы env, cmd и opts передаются в #popen3, за исключением opts[:stdin_data] и opts[:binmode]. См. Process.spawn.
Если указан opts[:stdin_data], он передаётся на стандартный ввод команды.
Если opts[:binmode] имеет значение true, внутренние каналы настроены на двоичный режим.
Примеры:
# dot is a command of graphviz.
graph = <<'End'
digraph g {
a -> b
}
End
drawn_graph, dot_log = Open3.capture3("dot -v", :stdin_data=>graph)
o, e, s = Open3.capture3("echo abc; sort >&2", :stdin_data=>"foo\nbar\nbaz\n")
p o #=> "abc\n"
p e #=> "bar\nbaz\nfoo\n"
p s #=> #<Process::Status: pid 32682 exit 0>
# generate a thumbnail image using the convert command of ImageMagick.
# However, if the image is really stored in a file,
# system("convert", "-thumbnail", "80", "png:#{filename}", "png:-") is better
# because of reduced memory consumption.
# But if the image is stored in a DB or generated by the gnuplot Open3.capture2 example,
# Open3.capture3 should be considered.
#
image = File.read("/usr/share/openclipart/png/animals/mammals/sheep-md-v0.1.png", :binmode=>true)
thumbnail, err, s = Open3.capture3("convert -thumbnail 80 png:- png:-", :stdin_data=>image, :binmode=>true)
if s.success?
STDOUT.binmode; print thumbnail
end
# File lib/open3.rb, line 601
def pipeline(*cmds, **opts)
pipeline_run(cmds, opts, [], []) {|ts|
ts.map(&:value)
}
end #pipeline запускает список команд как конвейер. Ждёт завершения команд. Каналы stdin первой команды и stdout последней команды не создаются.
status_list = Open3.pipeline(cmd1, cmd2, ... [, opts])
Каждая cmd — это строка или массив. Если это массив, элементы передаются в Process.spawn.
cmd: commandline command line string which is passed to a shell [env, commandline, opts] command line string which is passed to a shell [env, cmdname, arg1, ..., opts] command name and one or more arguments (no shell) [env, [cmdname, argv0], arg1, ..., opts] command name and arguments including argv[0] (no shell) Note that env and opts are optional, as Process.spawn.
Пример:
fname = "/usr/share/man/man1/ruby.1.gz"
p Open3.pipeline(["zcat", fname], "nroff -man", "less")
#=> [#<Process::Status: pid 11817 exit 0>,
# #<Process::Status: pid 11820 exit 0>,
# #<Process::Status: pid 11828 exit 0>]
fname = "/usr/share/man/man1/ls.1.gz"
Open3.pipeline(["zcat", fname], "nroff -man", "colcrt")
# convert PDF to PS and send to a printer by lpr
pdf_file = "paper.pdf"
printer = "printer-name"
Open3.pipeline(["pdftops", pdf_file, "-"],
["lpr", "-P#{printer}"])
# count lines
Open3.pipeline("sort", "uniq -c", :in=>"names.txt", :out=>"count")
# cyclic pipeline
r,w = IO.pipe
w.print "ibase=14\n10\n"
Open3.pipeline("bc", "tee /dev/tty", :in=>r, :out=>w)
#=> 14
# 18
# 22
# 30
# 42
# 58
# 78
# 106
# 202
# File lib/open3.rb, line 450 def pipeline_r(*cmds, **opts, &block) out_r, out_w = IO.pipe opts[:out] = out_w pipeline_run(cmds, opts, [out_w], [out_r], &block) end
#pipeline_r запускает список команд как конвейер с каналом, подключённым к stdout последней команды.
Open3.pipeline_r(cmd1, cmd2, ... [, opts]) {|last_stdout, wait_threads|
...
}
last_stdout, wait_threads = Open3.pipeline_r(cmd1, cmd2, ... [, opts])
...
last_stdout.close Каждая cmd — это строка или массив. Если это массив, элементы передаются в Process.spawn.
cmd: commandline command line string which is passed to a shell [env, commandline, opts] command line string which is passed to a shell [env, cmdname, arg1, ..., opts] command name and one or more arguments (no shell) [env, [cmdname, argv0], arg1, ..., opts] command name and arguments including argv[0] (no shell) Note that env and opts are optional, as for Process.spawn.
Пример:
Open3.pipeline_r("zcat /var/log/apache2/access.log.*.gz",
[{"LANG"=>"C"}, "grep", "GET /favicon.ico"],
"logresolve") {|o, ts|
o.each_line {|line|
...
}
}
Open3.pipeline_r("yes", "head -10") {|o, ts|
p o.read #=> "y\ny\ny\ny\ny\ny\ny\ny\ny\ny\n"
p ts[0].value #=> #<Process::Status: pid 24910 SIGPIPE (signal 13)>
p ts[1].value #=> #<Process::Status: pid 24913 exit 0>
} # File lib/open3.rb, line 400 def pipeline_rw(*cmds, **opts, &block) 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
#pipeline_rw запускает список команд как конвейер с каналами, подключёнными к stdin первой команды и stdout последней команды.
Open3.pipeline_rw(cmd1, cmd2, ... [, opts]) {|first_stdin, last_stdout, wait_threads|
...
}
first_stdin, last_stdout, wait_threads = Open3.pipeline_rw(cmd1, cmd2, ... [, opts])
...
first_stdin.close
last_stdout.close Опции для передачи в Process.spawn формируются путём объединения opts, последнего элемента хеша массива, и спецификаций каналов между каждой из команд.
Пример:
Open3.pipeline_rw("tr -dc A-Za-z", "wc -c") {|i, o, ts|
i.puts "All persons more than a mile high to leave the court."
i.close
p o.gets #=> "42\n"
}
Open3.pipeline_rw("sort", "cat -n") {|stdin, stdout, wait_thrs|
stdin.puts "foo"
stdin.puts "bar"
stdin.puts "baz"
stdin.close # send EOF to sort.
p stdout.read #=> " 1\tbar\n 2\tbaz\n 3\tfoo\n"
}
# File lib/open3.rb, line 539
def pipeline_start(*cmds, **opts, &block)
if block
pipeline_run(cmds, opts, [], [], &block)
else
ts, = pipeline_run(cmds, opts, [], [])
ts
end
end #pipeline_start запускает список команд как конвейер. Каналы stdin первой команды и stdout последней команды не создаются.
Open3.pipeline_start(cmd1, cmd2, ... [, opts]) {|wait_threads|
...
}
wait_threads = Open3.pipeline_start(cmd1, cmd2, ... [, opts])
... Каждая cmd — это строка или массив. Если это массив, элементы передаются в Process.spawn.
cmd: commandline command line string which is passed to a shell [env, commandline, opts] command line string which is passed to a shell [env, cmdname, arg1, ..., opts] command name and one or more arguments (no shell) [env, [cmdname, argv0], arg1, ..., opts] command name and arguments including argv[0] (no shell) Note that env and opts are optional, as for Process.spawn.
Пример:
# Run xeyes in 10 seconds.
Open3.pipeline_start("xeyes") {|ts|
sleep 10
t = ts[0]
Process.kill("TERM", t.pid)
p t.value #=> #<Process::Status: pid 911 SIGTERM (signal 15)>
}
# Convert pdf to ps and send it to a printer.
# Collect error message of pdftops and lpr.
pdf_file = "paper.pdf"
printer = "printer-name"
err_r, err_w = IO.pipe
Open3.pipeline_start(["pdftops", pdf_file, "-"],
["lpr", "-P#{printer}"],
:err=>err_w) {|ts|
err_w.close
p err_r.read # error messages of pdftops and lpr.
}
# File lib/open3.rb, line 486 def pipeline_w(*cmds, **opts, &block) in_r, in_w = IO.pipe opts[:in] = in_r in_w.sync = true pipeline_run(cmds, opts, [in_r], [in_w], &block) end
#pipeline_w запускает список команд как конвейер с каналом, подключённым к stdin первой команды.
Open3.pipeline_w(cmd1, cmd2, ... [, opts]) {|first_stdin, wait_threads|
...
}
first_stdin, wait_threads = Open3.pipeline_w(cmd1, cmd2, ... [, opts])
...
first_stdin.close Каждая cmd — это строка или массив. Если это массив, элементы передаются в Process.spawn.
cmd: commandline command line string which is passed to a shell [env, commandline, opts] command line string which is passed to a shell [env, cmdname, arg1, ..., opts] command name and one or more arguments (no shell) [env, [cmdname, argv0], arg1, ..., opts] command name and arguments including argv[0] (no shell) Note that env and opts are optional, as for Process.spawn.
Пример:
Open3.pipeline_w("bzip2 -c", :out=>"/tmp/hello.bz2") {|i, ts|
i.puts "hello"
}
# File lib/open3.rb, line 138 def popen2(*cmd, **opts, &block) 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
#popen2 аналогичен #popen3, за исключением того, что не создаёт канал для потока стандартной ошибки.
Блочный формат:
Open3.popen2([env,] cmd... [, opts]) {|stdin, stdout, wait_thr|
pid = wait_thr.pid # pid of the started process.
...
exit_status = wait_thr.value # Process::Status object returned.
} Неблочный формат:
stdin, stdout, wait_thr = Open3.popen2([env,] cmd... [, opts]) ... stdin.close # stdin and stdout should be closed explicitly in this form. stdout.close
См. Process.spawn для необязательных аргументов env и opts.
Пример:
Open3.popen2("wc -c") {|i,o,t|
i.print "answer to life the universe and everything"
i.close
p o.gets #=> "42\n"
}
Open3.popen2("bc -q") {|i,o,t|
i.puts "obase=13"
i.puts "6 * 9"
p o.gets #=> "42\n"
}
Open3.popen2("dc") {|i,o,t|
i.print "42P"
i.close
p o.read #=> "*"
}
# File lib/open3.rb, line 181 def popen2e(*cmd, **opts, &block) 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) end
#popen2e аналогичен #popen3, за исключением того, что объединяет потоки стандартного вывода и стандартной ошибки.
Блочный формат:
Open3.popen2e([env,] cmd... [, opts]) {|stdin, stdout_and_stderr, wait_thr|
pid = wait_thr.pid # pid of the started process.
...
exit_status = wait_thr.value # Process::Status object returned.
} Неблочный формат:
stdin, stdout_and_stderr, wait_thr = Open3.popen2e([env,] cmd... [, opts]) ... stdin.close # stdin and stdout_and_stderr should be closed explicitly in this form. stdout_and_stderr.close
См. Process.spawn для необязательных аргументов env и opts.
Пример:
# check gcc warnings
source = "foo.c"
Open3.popen2e("gcc", "-Wall", source) {|i,oe,t|
oe.each {|line|
if /warning/ =~ line
...
end
}
} # File lib/open3.rb, line 83 def popen3(*cmd, **opts, &block) 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
Открывает каналы stdin, stdout и stderr и запускает внешнее исполняемое приложение. Кроме того, создаётся поток для ожидания завершения запущенного процесса. Поток имеет метод pid и переменную thread :pid, которая является значением pid запущенного процесса.
Блочный формат:
Open3.popen3([env,] cmd... [, opts]) {|stdin, stdout, stderr, wait_thr|
pid = wait_thr.pid # pid of the started process.
...
exit_status = wait_thr.value # Process::Status object returned.
} Неблочный формат:
stdin, stdout, stderr, wait_thr = Open3.popen3([env,] cmd... [, opts]) pid = wait_thr[:pid] # pid of the started process ... stdin.close # stdin, stdout and stderr should be closed explicitly in this form. stdout.close stderr.close exit_status = wait_thr.value # Process::Status object returned.
Параметры env, cmd и opts передаются в Process.spawn. В качестве команды могут быть приняты строка командной строки и список строк аргументов следующим образом:
Open3.popen3("echo abc") {|i, o, e, t| ... }
Open3.popen3("echo", "abc") {|i, o, e, t| ... }
Open3.popen3(["echo", "argv0"], "abc") {|i, o, e, t| ... } Если последний параметр, opts, является Hash, он распознаётся как опция для Process.spawn.
Open3.popen3("pwd", :chdir=>"/") {|i,o,e,t|
p o.read.chomp #=> "/"
}
wait_thr.value ожидает завершения процесса. Блочный формат также ожидает завершения процесса при возврате.
Закрытие stdin, stdout и stderr не ожидает завершения процесса.
Следует быть внимательным, чтобы избежать тупиковых ситуаций. Поскольку каналы имеют буферы фиксированной длины, #popen3(“prog”) {|i, o, e, t| o.read } приводит к тупику, если программа генерирует слишком много вывода в stderr. Вы должны читать stdout и stderr одновременно (используя потоки или IO.select). Однако, если вам не нужен вывод stderr, вы можете использовать #popen2. Если объединение stdout и stderr не проблема, вы можете использовать #popen2e. Если вам действительно нужны stdout и stderr как отдельные строки, вы можете рассмотреть #capture3.
Методы экземпляра (приватные)
# File lib/open3.rb, line 304
def capture2(*cmd, stdin_data: nil, binmode: false, **opts)
popen2(*cmd, opts) {|i, o, t|
if binmode
i.binmode
o.binmode
end
out_reader = Thread.new { o.read }
if stdin_data
begin
i.write stdin_data
rescue Errno::EPIPE
end
end
i.close
[out_reader.value, t.value]
}
end #capture2 захватывает стандартный вывод команды.
stdout_str, status = Open3.capture2([env,] cmd... [, opts])
Аргументы env, cmd и opts передаются в #popen3, за исключением opts[:stdin_data] и opts[:binmode]. См. Process.spawn.
Если opts[:stdin_data] указано, оно отправляется на стандартный ввод команды.
Если opts[:binmode] равно true, внутренние каналы устанавливаются в двоичный режим.
Пример:
# factor is a command for integer factorization.
o, s = Open3.capture2("factor", :stdin_data=>"42")
p o #=> "42: 2 3 7\n"
# generate x**2 graph in png using gnuplot.
gnuplot_commands = <<"End"
set terminal png
plot x**2, "-" with lines
1 14
2 1
3 8
4 5
e
End
image, s = Open3.capture2("gnuplot", :stdin_data=>gnuplot_commands, :binmode=>true)
# File lib/open3.rb, line 339
def capture2e(*cmd, stdin_data: nil, binmode: false, **opts)
popen2e(*cmd, opts) {|i, oe, t|
if binmode
i.binmode
oe.binmode
end
outerr_reader = Thread.new { oe.read }
if stdin_data
begin
i.write stdin_data
rescue Errno::EPIPE
end
end
i.close
[outerr_reader.value, t.value]
}
end #capture2e захватывает стандартный вывод и стандартную ошибку команды.
stdout_and_stderr_str, status = Open3.capture2e([env,] cmd... [, opts])
Аргументы env, cmd и opts передаются в #popen3, за исключением opts[:stdin_data] и opts[:binmode]. См. Process.spawn.
Если opts[:stdin_data] указано, оно отправляется на стандартный ввод команды.
Если opts[:binmode] равно true, внутренние каналы устанавливаются в двоичный режим.
Пример:
# capture make log
make_log, s = Open3.capture2e("make")
# File lib/open3.rb, line 256
def capture3(*cmd, stdin_data: '', binmode: false, **opts)
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
i.write stdin_data
rescue Errno::EPIPE
end
i.close
[out_reader.value, err_reader.value, t.value]
}
end #capture3 захватывает стандартный вывод и стандартную ошибку команды.
stdout_str, stderr_str, status = Open3.capture3([env,] cmd... [, opts])
Аргументы env, cmd и opts передаются в #popen3, за исключением opts[:stdin_data] и opts[:binmode]. См. Process.spawn.
Если opts[:stdin_data] указано, оно отправляется на стандартный ввод команды.
Если opts[:binmode] равно true, внутренние каналы устанавливаются в двоичный режим.
Примеры:
# dot is a command of graphviz.
graph = <<'End'
digraph g {
a -> b
}
End
drawn_graph, dot_log = Open3.capture3("dot -v", :stdin_data=>graph)
o, e, s = Open3.capture3("echo abc; sort >&2", :stdin_data=>"foo\nbar\nbaz\n")
p o #=> "abc\n"
p e #=> "bar\nbaz\nfoo\n"
p s #=> #<Process::Status: pid 32682 exit 0>
# generate a thumbnail image using the convert command of ImageMagick.
# However, if the image is really stored in a file,
# system("convert", "-thumbnail", "80", "png:#{filename}", "png:-") is better
# because of reduced memory consumption.
# But if the image is stored in a DB or generated by the gnuplot Open3.capture2 example,
# Open3.capture3 should be considered.
#
image = File.read("/usr/share/openclipart/png/animals/mammals/sheep-md-v0.1.png", :binmode=>true)
thumbnail, err, s = Open3.capture3("convert -thumbnail 80 png:- png:-", :stdin_data=>image, :binmode=>true)
if s.success?
STDOUT.binmode; print thumbnail
end
# File lib/open3.rb, line 601
def pipeline(*cmds, **opts)
pipeline_run(cmds, opts, [], []) {|ts|
ts.map(&:value)
}
end #pipeline запускает список команд как конвейер. Ждет завершения команд. Каналы stdin первой команды и stdout последней команды не создаются.
status_list = Open3.pipeline(cmd1, cmd2, ... [, opts])
Каждая cmd — это строка или массив. Если массив, его элементы передаются в Process.spawn.
cmd: commandline command line string which is passed to a shell [env, commandline, opts] command line string which is passed to a shell [env, cmdname, arg1, ..., opts] command name and one or more arguments (no shell) [env, [cmdname, argv0], arg1, ..., opts] command name and arguments including argv[0] (no shell) Note that env and opts are optional, as Process.spawn.
Пример:
fname = "/usr/share/man/man1/ruby.1.gz"
p Open3.pipeline(["zcat", fname], "nroff -man", "less")
#=> [#<Process::Status: pid 11817 exit 0>,
# #<Process::Status: pid 11820 exit 0>,
# #<Process::Status: pid 11828 exit 0>]
fname = "/usr/share/man/man1/ls.1.gz"
Open3.pipeline(["zcat", fname], "nroff -man", "colcrt")
# convert PDF to PS and send to a printer by lpr
pdf_file = "paper.pdf"
printer = "printer-name"
Open3.pipeline(["pdftops", pdf_file, "-"],
["lpr", "-P#{printer}"])
# count lines
Open3.pipeline("sort", "uniq -c", :in=>"names.txt", :out=>"count")
# cyclic pipeline
r,w = IO.pipe
w.print "ibase=14\n10\n"
Open3.pipeline("bc", "tee /dev/tty", :in=>r, :out=>w)
#=> 14
# 18
# 22
# 30
# 42
# 58
# 78
# 106
# 202
# File lib/open3.rb, line 450 def pipeline_r(*cmds, **opts, &block) out_r, out_w = IO.pipe opts[:out] = out_w pipeline_run(cmds, opts, [out_w], [out_r], &block) end
#pipeline_r запускает список команд как конвейер с каналом, подключенным к stdout последней команды.
Open3.pipeline_r(cmd1, cmd2, ... [, opts]) {|last_stdout, wait_threads|
...
}
last_stdout, wait_threads = Open3.pipeline_r(cmd1, cmd2, ... [, opts])
...
last_stdout.close Каждая cmd — это строка или массив. Если массив, его элементы передаются в Process.spawn.
cmd: commandline command line string which is passed to a shell [env, commandline, opts] command line string which is passed to a shell [env, cmdname, arg1, ..., opts] command name and one or more arguments (no shell) [env, [cmdname, argv0], arg1, ..., opts] command name and arguments including argv[0] (no shell) Note that env and opts are optional, as for Process.spawn.
Пример:
Open3.pipeline_r("zcat /var/log/apache2/access.log.*.gz",
[{"LANG"=>"C"}, "grep", "GET /favicon.ico"],
"logresolve") {|o, ts|
o.each_line {|line|
...
}
}
Open3.pipeline_r("yes", "head -10") {|o, ts|
p o.read #=> "y\ny\ny\ny\ny\ny\ny\ny\ny\ny\n"
p ts[0].value #=> #<Process::Status: pid 24910 SIGPIPE (signal 13)>
p ts[1].value #=> #<Process::Status: pid 24913 exit 0>
} # File lib/open3.rb, line 400 def pipeline_rw(*cmds, **opts, &block) 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
#pipeline_rw запускает список команд как конвейер с каналами, подключенными к stdin первой команды и stdout последней команды.
Open3.pipeline_rw(cmd1, cmd2, ... [, opts]) {|first_stdin, last_stdout, wait_threads|
...
}
first_stdin, last_stdout, wait_threads = Open3.pipeline_rw(cmd1, cmd2, ... [, opts])
...
first_stdin.close
last_stdout.close Каждая cmd — это строка или массив. Если массив, его элементы передаются в Process.spawn.
cmd: commandline command line string which is passed to a shell [env, commandline, opts] command line string which is passed to a shell [env, cmdname, arg1, ..., opts] command name and one or more arguments (no shell) [env, [cmdname, argv0], arg1, ..., opts] command name and arguments including argv[0] (no shell) Note that env and opts are optional, as for Process.spawn.
Опции для передачи в Process.spawn конструируются путём слияния opts, последнего элемента хеша в массиве, и спецификаций каналов между каждой из команд.
Пример:
Open3.pipeline_rw("tr -dc A-Za-z", "wc -c") {|i, o, ts|
i.puts "All persons more than a mile high to leave the court."
i.close
p o.gets #=> "42\n"
}
Open3.pipeline_rw("sort", "cat -n") {|stdin, stdout, wait_thrs|
stdin.puts "foo"
stdin.puts "bar"
stdin.puts "baz"
stdin.close # send EOF to sort.
p stdout.read #=> " 1\tbar\n 2\tbaz\n 3\tfoo\n"
}
# File lib/open3.rb, line 539
def pipeline_start(*cmds, **opts, &block)
if block
pipeline_run(cmds, opts, [], [], &block)
else
ts, = pipeline_run(cmds, opts, [], [])
ts
end
end #pipeline_start запускает список команд как конвейер. Каналы stdin первой команды и stdout последней команды не создаются.
Open3.pipeline_start(cmd1, cmd2, ... [, opts]) {|wait_threads|
...
}
wait_threads = Open3.pipeline_start(cmd1, cmd2, ... [, opts])
... Каждая cmd — это строка или массив. Если массив, его элементы передаются в Process.spawn.
cmd: commandline command line string which is passed to a shell [env, commandline, opts] command line string which is passed to a shell [env, cmdname, arg1, ..., opts] command name and one or more arguments (no shell) [env, [cmdname, argv0], arg1, ..., opts] command name and arguments including argv[0] (no shell) Note that env and opts are optional, as for Process.spawn.
Пример:
# Run xeyes in 10 seconds.
Open3.pipeline_start("xeyes") {|ts|
sleep 10
t = ts[0]
Process.kill("TERM", t.pid)
p t.value #=> #<Process::Status: pid 911 SIGTERM (signal 15)>
}
# Convert pdf to ps and send it to a printer.
# Collect error message of pdftops and lpr.
pdf_file = "paper.pdf"
printer = "printer-name"
err_r, err_w = IO.pipe
Open3.pipeline_start(["pdftops", pdf_file, "-"],
["lpr", "-P#{printer}"],
:err=>err_w) {|ts|
err_w.close
p err_r.read # error messages of pdftops and lpr.
}
# File lib/open3.rb, line 486 def pipeline_w(*cmds, **opts, &block) in_r, in_w = IO.pipe opts[:in] = in_r in_w.sync = true pipeline_run(cmds, opts, [in_r], [in_w], &block) end
#pipeline_w запускает список команд как конвейер с каналом, подключенным к stdin первой команды.
Open3.pipeline_w(cmd1, cmd2, ... [, opts]) {|first_stdin, wait_threads|
...
}
first_stdin, wait_threads = Open3.pipeline_w(cmd1, cmd2, ... [, opts])
...
first_stdin.close Каждая cmd — это строка или массив. Если массив, его элементы передаются в Process.spawn.
cmd: commandline command line string which is passed to a shell [env, commandline, opts] command line string which is passed to a shell [env, cmdname, arg1, ..., opts] command name and one or more arguments (no shell) [env, [cmdname, argv0], arg1, ..., opts] command name and arguments including argv[0] (no shell) Note that env and opts are optional, as for Process.spawn.
Пример:
Open3.pipeline_w("bzip2 -c", :out=>"/tmp/hello.bz2") {|i, ts|
i.puts "hello"
}
# File lib/open3.rb, line 138 def popen2(*cmd, **opts, &block) 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
#popen2 похож на #popen3, за исключением того, что он не создаёт канал для потока стандартной ошибки.
Блочный вид:
Open3.popen2([env,] cmd... [, opts]) {|stdin, stdout, wait_thr|
pid = wait_thr.pid # pid of the started process.
...
exit_status = wait_thr.value # Process::Status object returned.
} Неблочный вид:
stdin, stdout, wait_thr = Open3.popen2([env,] cmd... [, opts]) ... stdin.close # stdin and stdout should be closed explicitly in this form. stdout.close
См. Process.spawn для необязательных аргументов хеша env и opts.
Пример:
Open3.popen2("wc -c") {|i,o,t|
i.print "answer to life the universe and everything"
i.close
p o.gets #=> "42\n"
}
Open3.popen2("bc -q") {|i,o,t|
i.puts "obase=13"
i.puts "6 * 9"
p o.gets #=> "42\n"
}
Open3.popen2("dc") {|i,o,t|
i.print "42P"
i.close
p o.read #=> "*"
}
# File lib/open3.rb, line 181 def popen2e(*cmd, **opts, &block) 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) end
#popen2e похож на #popen3, за исключением того, что он объединяет потоки стандартного вывода и стандартной ошибки.
Блочный вид:
Open3.popen2e([env,] cmd... [, opts]) {|stdin, stdout_and_stderr, wait_thr|
pid = wait_thr.pid # pid of the started process.
...
exit_status = wait_thr.value # Process::Status object returned.
} Неблочный вид:
stdin, stdout_and_stderr, wait_thr = Open3.popen2e([env,] cmd... [, opts]) ... stdin.close # stdin and stdout_and_stderr should be closed explicitly in this form. stdout_and_stderr.close
См. Process.spawn для необязательных аргументов хеша env и opts.
Пример:
# check gcc warnings
source = "foo.c"
Open3.popen2e("gcc", "-Wall", source) {|i,oe,t|
oe.each {|line|
if /warning/ =~ line
...
end
}
} # File lib/open3.rb, line 83 def popen3(*cmd, **opts, &block) 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
Открывает потоки stdin, stdout и stderr и запускает внешнюю исполняемую программу. Кроме того, создаётся поток для ожидания завершения запущенного процесса. У потока есть метод pid и переменная :pid, которая содержит pid запущенного процесса.
Блочный вид:
Open3.popen3([env,] cmd... [, opts]) {|stdin, stdout, stderr, wait_thr|
pid = wait_thr.pid # pid of the started process.
...
exit_status = wait_thr.value # Process::Status object returned.
} Неблочный вид:
stdin, stdout, stderr, wait_thr = Open3.popen3([env,] cmd... [, opts]) pid = wait_thr[:pid] # pid of the started process ... stdin.close # stdin, stdout and stderr should be closed explicitly in this form. stdout.close stderr.close exit_status = wait_thr.value # Process::Status object returned.
Параметры env, cmd и opts передаются в Process.spawn. Можно принимать строку командной строки и список строк аргументов следующим образом:
Open3.popen3("echo abc") {|i, o, e, t| ... }
Open3.popen3("echo", "abc") {|i, o, e, t| ... }
Open3.popen3(["echo", "argv0"], "abc") {|i, o, e, t| ... } Если последний параметр, opts, является хешем, он распознаётся как опция для Process.spawn.
Open3.popen3("pwd", :chdir=>"/") {|i,o,e,t|
p o.read.chomp #=> "/"
}
wait_thr.value ждёт завершения процесса. Блочный вид также ждёт завершения процесса при возвращении.
Закрытие stdin, stdout и stderr не ждёт завершения процесса.
Следует быть осторожным, чтобы избежать тупиковых ситуаций. Поскольку каналы имеют буферы фиксированной длины, #popen3(“prog”) {|i, o, e, t| o.read } может привести к тупику, если программа генерирует слишком много вывода в stderr. Необходимо читать stdout и stderr одновременно (используя потоки или IO.select). Однако, если вывод stderr не требуется, можно использовать #popen2. Если объединение stdout и stderr не представляет проблемы, можно использовать #popen2e. Если вам действительно нужны stdout и stderr как отдельные строки, можно рассмотреть #capture3.
Ruby Core © 1993–2017 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.