41.3 Создание синхронного процесса

После создания синхронного процесса Emacs ожидает завершения этого процесса перед продолжением работы. Примером этого является запуск Dired в GNU или Unix29: он запускает ls в синхронном процессе, а затем слегка изменяет вывод. Поскольку процесс синхронный, весь список каталога поступает в буфер до того, как Emacs попытается что-либо с ним сделать.

Пока Emacs ожидает завершения синхронного подпроцесса, пользователь может прервать выполнение, набрав C-g. Первое нажатие C-g пытается завершить подпроцесс сигналом SIGINT, но ожидает фактического завершения подпроцесса перед выходом. Если за это время пользователь нажмет еще раз C-g, это мгновенно завершит подпроцесс сигналом SIGKILL и немедленно выйдет (кроме MS-DOS, где завершение других процессов не работает). См. Прерывание.

Функции синхронных подпроцессов возвращают индикацию того, как завершился процесс.

Вывод из синхронного подпроцесса обычно декодируется с использованием кодировки, подобно тексту, читаемому из файла. Ввод, отправляемый подпроцессу функцией call-process-region, кодируется с использованием кодировки, подобно тексту, записываемому в файл. См. Системы кодирования.

Функция: call-process program &optional infile destination display &rest args

Эта функция вызывает program и ожидает его завершения.

Рабочий каталог подпроцесса устанавливается в значение default-directory текущего буфера, если оно локально (определяется функцией unhandled-file-name-directory), или в "~" в противном случае. Если вы хотите запустить процесс в удаленном каталоге, используйте process-file.

Стандартный ввод для нового процесса поступает из файла infile, если infile не равен nil, и из нулевого устройства в противном случае. Аргумент destination указывает, куда помещать вывод процесса. Вот возможные варианты:

буфер

Вставить вывод в этот буфер перед точкой. Сюда входит как стандартный поток вывода, так и стандартный поток ошибок процесса.

имя буфера (строка)

Вставить вывод в буфер с этим именем перед точкой.

t

Вставить вывод в текущий буфер перед точкой.

nil

Отбросить вывод.

0

Отбросить вывод и сразу вернуть nil, не дожидаясь завершения подпроцесса.

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

MS-DOS не поддерживает асинхронные подпроцессы, поэтому этот параметр там не работает.

(:file file-name)

Направить вывод в указанное имя файла, перезаписывая его, если он уже существует.

(real-destination error-destination)

Разделить стандартный поток вывода и стандартный поток ошибок; обрабатывать обычный вывод, как указано в real-destination, и направлять вывод ошибок согласно error-destination. Если error-destination равен nil, это означает отбросить вывод ошибок, t означает смешивать его с обычным выводом, а строка указывает имя файла для перенаправления вывода ошибок.

Вы не можете напрямую указать буфер для вывода ошибок; это слишком сложно для реализации. Но вы можете достичь этого результата, направив вывод ошибок во временный файл, а затем вставив его в буфер после завершения подпроцесса.

Если display не равен nil, то call-process перерисовывает буфер по мере вставки вывода. (Однако если выбранная для декодирования вывода система кодирования — undecided, то есть определение кодировки по фактическим данным, то перерисовка иногда не может продолжаться после обнаружения не-ASCII символов. Существуют фундаментальные причины, по которым это сложно исправить; см. Получение вывода от процессов.)

В противном случае функция call-process не выполняет перерисовки, и результаты становятся видимыми на экране только тогда, когда Emacs перерисовывает этот буфер в обычном порядке.

Остальные аргументы, args, являются строками, задающими аргументы командной строки для программы. Каждая строка передается program как отдельный аргумент.

Возвращаемое значение call-process (если вы не указали не ждать) указывает причину завершения процесса. Число означает код завершения подпроцесса; 0 означает успех, а любое другое значение — ошибку. Если процесс был завершен сигналом, call-process возвращает строку, описывающую сигнал. Если вы указали call-process не ждать, он возвращает nil.

В примерах ниже текущим является буфер ‘foo’.

(call-process "pwd" nil t)
     ⇒ 0

---------- Буфер: foo ----------
/home/lewis/manual
---------- Буфер: foo ----------

(call-process "grep" nil "bar" nil "lewis" "/etc/passwd")
     ⇒ 0

---------- Буфер: bar ----------
lewis:x:1001:1001:Bil Lewis,,,,:/home/lewis:/bin/bash

---------- Буфер: bar ----------

Вот пример использования call-process, который ранее использовался в определении функции insert-directory:

(call-process insert-directory-program nil t nil switches
              (if full-directory-p
                  (concat (file-name-as-directory file) ".")
                file))
Функция: process-file program &optional infile buffer display &rest args

Эта функция обрабатывает файлы синхронно в отдельном процессе. Она аналогична call-process, но может вызывать обработчик имен файлов на основе значения переменной default-directory, которая задает текущий рабочий каталог подпроцесса.

Аргументы обрабатываются почти так же, как и для call-process, со следующими отличиями:

Некоторые обработчики имен файлов могут не поддерживать все комбинации и формы аргументов infile, buffer и display. Например, некоторые обработчики имен файлов могут вести себя так, как если бы display был равен nil, независимо от фактически переданного значения. В качестве другого примера, некоторые обработчики имен файлов могут не поддерживать разделение стандартного вывода и вывода ошибок через аргумент buffer.

Если вызывается обработчик имен файлов, он определяет программу для запуска на основе первого аргумента program. Например, предположим, что вызывается обработчик для удаленных файлов. Тогда путь, используемый для поиска программы, может отличаться от exec-path.

Второй аргумент infile может вызывать обработчик имен файлов. Обработчик имен файлов может отличаться от обработчика, выбранного для самой функции process-file. (Например, default-directory может находиться на одном удаленном хосте, а infile — на другом. Или default-directory может быть обычным, тогда как infile находится на удаленном хосте.)

Если buffer является списком вида (real-destination error-destination) и error-destination указывает на файл, то применяются те же замечания, что и для infile.

Остальные аргументы (args) будут переданы процессу без изменений. Emacs не участвует в обработке имен файлов, присутствующих в args. Во избежание путаницы лучше избегать абсолютных имен файлов в args, а указывать все имена файлов относительно default-directory. Функция file-relative-name полезна для создания таких относительных имен файлов. Альтернативно, вы можете использовать file-local-name (см. Создание "волшебных" имен файлов), чтобы получить абсолютное имя файла с точки зрения удаленного хоста.

Переменная: process-file-side-effects

Эта переменная указывает, изменяет ли вызов process-file удаленные файлы.

По умолчанию эта переменная всегда установлена в t, что означает, что вызов process-file потенциально может изменить любой файл на удаленном хосте. Когда она установлена в nil, обработчик имен файлов может оптимизировать свое поведение в отношении кеширования атрибутов удаленных файлов.

Вы должны изменять эту переменную только с помощью let-привязки; никогда не используйте setq.

Пользовательская опция: process-file-return-signal-string

Эта пользовательская опция указывает, возвращает ли вызов process-file строку, описывающую сигнал, прервавший удаленный процесс.

Когда процесс возвращает код выхода больше 128, это интерпретируется как сигнал. process-file должен возвращать строку, описывающую этот сигнал.

Поскольку существуют процессы, нарушающие это правило и возвращающие коды выхода больше 128, которые не связаны с сигналом, process-file всегда возвращает код выхода как натуральное число для удаленных процессов. Установка этой пользовательской опции в не-nil заставляет process-file интерпретировать такие коды выхода как сигналы и возвращать соответствующую строку.

Функция: call-process-region start end program &optional delete destination display &rest args

Эта функция отправляет текст от start до end как стандартный ввод процессу, выполняющему program. Она удаляет отправленный текст, если delete не равен nil; это полезно, когда destination равен t, чтобы вставить вывод в текущий буфер вместо ввода.

Аргументы destination и display управляют тем, что делать с выводом подпроцесса и обновлять ли дисплей по мере поступления данных. Подробности см. в описании call-process выше. Если destination равно целому числу 0, call-process-region отбрасывает вывод и немедленно возвращает nil, не дожидаясь завершения подпроцесса (это работает только при поддержке асинхронных подпроцессов, т.е. не на MS-DOS).

Остальные аргументы, args, являются строками, задающими аргументы командной строки для программы.

Возвращаемое значение call-process-region аналогично возвращаемому значению call-process: nil, если вы указали вернуться без ожидания; в противном случае число или строка, указывающие, как завершился подпроцесс.

В следующем примере мы используем call-process-region для запуска утилиты cat, при этом стандартным вводом являются первые пять символов в буфере ‘foo’ (слово ‘input’). cat копирует свой стандартный ввод в стандартный вывод. Поскольку аргумент destination равен t, этот вывод вставляется в текущий буфер.

---------- Буфер: foo ----------
input∗
---------- Буфер: foo ----------

(call-process-region 1 6 "cat" nil t)
     ⇒ 0

---------- Буфер: foo ----------
inputinput∗
---------- Буфер: foo ----------

Например, команда shell-command-on-region использует call-shell-region аналогичным образом:

(call-shell-region
 start end
 command              ; команда оболочки
 nil                  ; не удалять область
 buffer)              ; отправить вывод в buffer
Функция: call-process-shell-command command &optional infile destination display

Эта функция выполняет команду оболочки command синхронно. Остальные аргументы обрабатываются так же, как в call-process. Старое соглашение о вызове позволяло передавать любое количество дополнительных аргументов после display, которые объединялись с command; это все еще поддерживается, но настоятельно не рекомендуется.

Функция: process-file-shell-command command &optional infile destination display

Эта функция подобна call-process-shell-command, но внутренне использует process-file. В зависимости от default-directory, command может выполняться также на удаленных хостах. Старое соглашение о вызове позволяло передавать любое количество дополнительных аргументов после display, которые объединялись с command; это все еще поддерживается, но настоятельно не рекомендуется.

Функция: call-shell-region start end command &optional delete destination

Эта функция отправляет текст от start до end как стандартный ввод вложенной оболочке, выполняющей command. Эта функция аналогична call-process-region, но процессом является оболочка. Аргументы delete, destination и возвращаемое значение аналогичны call-process-region. Обратите внимание, что эта функция не принимает дополнительные аргументы.

Если command указывает на оболочку (например, через shell-file-name), имейте в виду, что поведение различных оболочек при передаче команд в их стандартный ввод зависит от оболочки и системы, и поэтому непереносимо. Различия особенно заметны, когда область включает более одной строки, то есть при передаче в оболочку команд с встроенными символами новой строки. Поэтому Lisp-программы, использующие этот метод, должны форматировать текст в области по-разному, в соответствии с ожиданиями оболочки.

Функция: shell-command-to-string command

Эта функция выполняет command (строку) как команду оболочки, а затем возвращает вывод команды в виде строки. Если command фактически содержит более одной команды, поведение зависит от вызываемой оболочки (определяется shell-file-name для локальных команд). В частности, разделитель между командами не может быть символом новой строки в MS-Windows; используйте вместо него ‘&&’.

Функция: process-lines program &rest args

Эта функция запускает program, ожидает его завершения и возвращает его вывод в виде списка строк. Каждая строка в списке содержит одну строку текста, выведенную программой; символы конца строки удаляются из каждой строки. Аргументы после program, args, являются строками, задающими аргументы командной строки для запуска программы.

Если program завершается с ненулевым кодом выхода, эта функция сигнализирует об ошибке.

Эта функция работает путем вызова call-process, поэтому вывод программы декодируется так же, как и для call-process.

Функция: process-lines-ignore-status program &rest args

Эта функция аналогична process-lines, но не сигнализирует об ошибке, если program завершается с ненулевым кодом выхода.


Сноски

(29)

В других системах Emacs использует Lisp-эмуляцию ls; см. Содержимое каталогов.