sleep 2
Process.kill(1,0) # Послать самому себе.
О применениях метода trap
в более сложных ситуациях читайте в документации по Ruby и UNIX.
В модуле Process
есть также методы для опроса и установки таких атрибутов процесса, как идентификатор пользователя, действующий идентификатор пользователя, приоритет и т.д. Дополнительную информацию вы отыщете в справочном руководстве по Ruby.
14.1.4. Стандартный ввод и вывод
В главе 10 мы видели, как работают методы IO.popen
и IO.pipe
, но существует еще небольшая библиотека, которая иногда бывает удобна.
В библиотеке Open3.rb
есть метод popen3
, который возвращает массив из трех объектов IO
. Они соответствуют стандартному вводу, стандартному выводу и стандартному выводу для ошибок того процесса, который был запущен методом popen3
. Вот пример:
require 'open3'
filenames = %w[ file1 file2 this that another one_more ]
inp, out, err = Open3.popen3('xargs', 'ls', '-l')
filenames.each { |f| inp.puts f } # Писать в stdin процесса.
inp.close # Закрывать обязательно!
output = out.readlines # Читать из stdout.
errout = err.readlines # Читать также из stderr.
puts 'Послано #{filenames.size} строк входных данных.'
puts 'Получено #{output.size} строк из stdout'
puts 'и #{errout.size} строк из stderr.'
В этом искусственном примере мы выполняем команду ls -l
для каждого из заданных имен файлов и по отдельности перехватываем стандартный вывод и стандартный вывод для ошибок. Отметим, что вызов close
необходим, чтобы порожденный процесс увидел конец файла. Также отметим, что в библиотеке Open3 используется метод fork
, не реализованный на платформе Windows; для этой платформы придется пользоваться библиотекой win32-open3
(ее написали и поддерживают Дэниэль Бергер (Daniel Berger) и Парк Хисоб (Park Heesob)). См. также раздел 14.3.
14.2. Флаги и аргументы в командной строке
Слухи о кончине командной строки сильно преувеличены. Хоть мы и живем в век графических интерфейсов, ежедневно тысячи и тысячи программистов по тем или иным причинам обращаются к командным утилитам.
Мы уже говорили, что корнями своими Ruby уходит в UNIX. Но даже в Windows существует понятие командной строки, и, честно говоря, мы не думаем, что в обозримом будущем она исчезнет.
На этом уровне для управления работой программы применяются аргументы и флаги. О них мы и поговорим ниже.
14.2.1. Разбор флагов в командной строке
Для разбора командной строки чаще всего применяется библиотека getoptlong
(библиотека getopts.rb
, обладающая менее развитой функциональностью, считается устаревшей). Она понимает однобуквенные и длинные флаги и распознает двойной дефис (--
) как признак конца флагов. В целом библиотека ведет себя так же, как соответствующие функции GNU.
Необходимо создать объект класса GetoptLong
, который и будет выполнять функции анализатора. Затем ему передаются допустимые значения флагов, а он извлекает их по одному.
У объекта-анализатора есть метод set_options
, который принимает список массивов. Каждый массив содержит один или несколько флагов (в виде строк) и один «признак наличия аргумента», который говорит, должны ли эти флаги сопровождаться аргументами. Все флаги в одном массиве считаются синонимами; первый из них является «каноническим именем», которое и возвращает операция get
.
Предположим, что имеется программа, понимающая следующие флаги: -h
или --help
(печать справки), -f
или --file
(указание имени файла), -l
или --lines
(вывод не более указанного числа строк, по умолчанию 100).
Такая программа могла бы начинаться следующим образом:
require 'getoptlong'
parser = GetoptLong.new
parser.set_options(
['-h', '--help', GetoptLong::NO_ARGUMENT],
['-f', '--file', GetoptLong::REQUIRED_ARGUMENT],
['-l', '--lines', GetoptLong::OPTIONAL_ARGUMENT])
Теперь можно в цикле вызвать метод get
(см. листинг 14.1). Наличие операторных скобок begin-end
имитирует цикл с проверкой условия в конце. У метода get
есть синоним get_option
, существуют также итераторы each
и each_option
, которые в точности идентичны.
filename = nil
lines = 0 # По умолчанию вывод не усекается.
loop do
begin
opt, arg = parser.get
break if not opt
# Только для отладки...
puts (opt +' => ' + arg)
case opt