понедельник, 18 марта 2019 г.

MiniM. Запуск внешнего процесса и взаимодействие с ним

Для задач интеграции и взаимодействия с внешними процессами в MiniM рассмотрим устройство типа |PIPE|.

Устройство типа |PIPE| представляет собой двунаправленное устройство ввода-вывода, запускающее указанный файл как процесс, передающий ему параметры запуска и выполняющее чтение-запись через виртуальный канал взаимодействия.

На стороне MiniM процесса взаимодействие выполняется через команды чтения и записи. На стороне запускаемого процесса данные передаются и принимаются через стандартные каналы stdin / stdout.

Дочерний процесс запускается через системную утилиту cmd.exe либо через ту утилиту, которая указана в переменной окружения ComSpec. Это позволяет запускать в качестве процессов как исполняемые образы в виде файлов .exe, так и ассоциированные с расширениями файлов обработчики, например файлы .bat, .cmd, .vbs и другие, а также команды операционной системы, не имеющие отдельного файла, например команду dir.

Кроме того, этот способ позволяет использовать процессор cmd.exe для перенаправления ввода - вывода процесса в файлы или между другими процессами.

Имя файла, по которому запускается процесс, и его параметры указываются в имени устройства, например:
s dev="|PIPE|dir /w"
это устройство запустит команду dir с параметром /w.

Дочерний процесс запускается при открытии устройства типа |PIPE|. Факт успешного открытия устройства означает, что процесс запущен. Дальнейшее выполнение дочернего процесса определяется его назначением.

Запуск дочернего процесса.

Для примера запуска дочернего процесса используем команду создания подкаталога.
s dev="|PIPE|mkdir subdir"
o dev
c dev
Здесь создается устройство для запуска mkdir с указанием параметра subdir. При открытии устройства процесс запускается. При закрытии устройства родительский процесс забывает о запущенном процессе. При выполнении этого примера создается дочерний подкаталог subdir.

Запуск дочернего процесса с перенаправлением вывода

Для перенаправления вывода дочернего процесса используется символ перенаправления > и указывается в спецификации имени устройства. Например, запуск команды dir с перенаправлением вывода в файл описывается так:
s dev="|PIPE|dir /w > dir.txt"
o dev
c dev
Здесь создается устройство типа |PIPE| для запуска процесса по встроенной команде dir с указанием параметра /w и перенаправлением его вывода в файл dir.txt. При выполнении этого примера создается файл dir.txt в котором сохранен вывод команды dir.

Запуск дочернего процесса с чтением его вывода в stdout

Для получения вывода дочернего процесса в его stdout нужно создать устройство типа |PIPE|, открыть его на чтение, сделать текущим и читать из текущего устройства.
dir ;
 n zeof=$v("proc",5,0)
 n dev="|PIPE|dir /w"
 o dev:("rwt")
 n result
 u dev f  q:$zeof  r result($i(result))
 u $p
 c dev
 i $v("proc",5,zeof)
 zw result
 q
В этом примере запускается дочерний процесс dir с параметром /w, устройство делается текущим и из него читается построчно в текстовом режиме результат вывода процесса.

Функции $v("proc",5) применяются для управления состоянием системной переменной $zeof чтобы не получить в конце чтения ошибку чтения.

Здесь чтение выполняется в локальную переменную result с помощью команды
r result($i(result))
По окончании чтения результат выводится в текущее устройство ввода-вывода в виде вывода состояния локальной переменной result.

Запуск дочернего процесса с записью в его канал stdin и чтением его вывода в stdout

Для запуска дочернего процесса с записью в его входной канал stdin и чтением из его выходного канала stdout используется устройство типа |PIPE| открытое на чтение и запись, которое надо сделать текущим, после чего писать в текущее устройство, затем читать из него.

В операционной системе Windows работа каналов stdin-stdout организована так, что если выполнено чтение из stdout дочернего процесса, то запись в его stdin уже невозможна. Процесс MiniM после первого чтения из устройства |PIPE| автоматически переводит его в режим только-чтение.

Приведем пример запуска дочернего процесса в виде команды sort. Эта команда читает то что подается на вход через канал stdin или через перенаправление ввода от другого процесса или из файла и выдает в свой выходной канал stdout отсортированные строки.
runext ;
 n zeof=$v("proc",5,0)
 n dev="|PIPE|sort",line
 o dev:("rwt")
 u dev
 n i=0 f  s i=$o(^ROUTINE($zname,i)) q:i=""  d
 . w $g(^ROUTINE($zname,i)),!
 f  q:$zeof  d
 . r line u $p w line,! u dev
 u $p
 c dev
 i $v("proc",5,zeof)
 q
В этом примере программа читает собственный текст их глобала ^ROUTINE построчно и записывает строки в входной канал дочернего процесса sort. После чего построчно вычитывает из устройства результат сортировки и выводит строки в свое текущее устройство. Как только выполняется первая команда чтения из дочернего процесса, входной канал дочернего процесса закрывается. Это служит сигналом дочернему процессу об окончании передачи ему данных, команда sort проводит сортировку строк и после этого их можно читать из выходного канала stdout.

Пример работы этой программы:
USER>d ^runext
 . r line u $p w line,! u dev
 . w $g(^ROUTINE($zname,i)),!
 c dev
 f  q:$zeof  d
 i $v("proc",5,zeof)
 n dev="|PIPE|sort",line
 n i=0 f  s i=$o(^ROUTINE($zname,i)) q:i=""  d
 n zeof=$v("proc",5,0)
 o dev:("rwt")
 q
 u $p
 u dev
runext ;

Комментариев нет:

Отправить комментарий