[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端]

36. プロセス

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp21&node=Processes"
"texi/elisp21/プロセス"へのコメント(無し)

オペレーティングシステムの用語では、 プロセス(process)とは、プログラムを実行する空間のことです。 Emacsはプロセスとして動いています。 Emacs Lispのプログラムでは、 独自のプロセスとして他のプログラムを起動できます。 それらは、Emacsプロセスのサブプロセス(subprocess)とか 子プロセス(child process)と呼ばれ、 Emacsプロセスはそれらの親プロセス(parent process)です。

Emacsのサブプロセスは、それを作成する方法に依存して、 同期(synchronous)であるか非同期(asynchronous)です。 同期サブプロセスを作成すると、 Lispプログラムは実行を継続するまえにそのサブプロセスの終了を待ちます。 非同期サブプロセスを作成すると、それはLispプログラムと並行して動作します。 この種のサブプロセスは、Emacs内部ではやはり『プロセス』と呼ばれる Lispオブジェクトで表現されます。 Lispプログラムはこのオブジェクトを用いて サブプロセスと通信したりそれを制御できます。 たとえば、シグナルを送ったり、状態情報を取得したり、 プロセスからの出力を受け取ったり、プロセスへ入力を送れます。

Function: processp object
この関数は、objectがプロセスであればtを返し、 さもなければnilを返す。



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端]

36.1 サブプロセス作成関数

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp21&node=Subprocess%20Creation"
"texi/elisp21/サブプロセス作成関数"へのコメント(無し)

プログラムを実行するために新たなサブプロセスを作る関数が3つあります。 その1つstart-processは、非同期プロセスを作成して プロセスオブジェクトを返します(see 節 36.4 非同期プロセスの作成)。 残りの2つ、call-processcall-process-regionは 同期プロセスを作成しますが、プロセスオブジェクトは返しません (see 節 36.3 同期プロセスの作成)。

同期/非同期プロセスについては以下の節に述べます。 3つの関数の呼び出し方は類似しているので、 ここではそれらに共通な引数について述べます。

いずれの場合でも、関数の引数programは、 実行すべきプログラムを指定します。 そのファイルがみつからなかったり実行できないと、 エラーを通知します。 ファイル名が相対名であると、 変数exec-pathは探索すべきディレクトリのリストを保持しています。 Emacsは起動時に環境変数PATHの値に基づいてexec-pathを 初期化します。 `~'、`.'、`..'のファイル名の標準的な書き方は、 exec-pathでも普通どおりに解釈されますが、 (`$HOME'などの)環境変数の置換は認識しません。 それにはsubstitute-in-file-nameを使います (see 節 24.8.4 ファイル名を展開する関数)。

サブプロセスを作成する各関数には、 プログラムの標準出力の受け取り場所を指定する 引数buffer-or-nameがあります。 これはバッファかバッファ名である必要があります。 バッファ名であると、そのバッファが既存でなければ新たに作成します。 nilでもかまいませんが、その場合、 フィルタ関数で処理しない限り出力を破棄します。 (36.9.2 プロセスフィルタ関数とsee 節 18. Lispオブジェクトの読み取りと表示)。 通常、複数のプロセスの出力を同じバッファへは送らないようにします。 それらの出力がでたらめに混ざってしまうからです。

サブプロセスを作成する3つの関数すべてに、 &rest引数であるargsがあります。 argsはすべてが文字列である必要があり、 それぞれを区切ってコマンド行引数としてprogramに与えられます。 引数全体を指定されたプログラムへ直接渡すため、 これらの引数ではワイルドカード文字や他のシェル構文の特別な意味はありません。

注意引数programにはプログラムの名前だけを指定し、 コマンド行引数はいっさい指定しない。 コマンド行引数はargsで与えること。

サブプロセスのカレントディレクトリは default-directoryの値で決まります(see 節 24.8.4 ファイル名を展開する関数)。

サブプロセスはEmacsから環境変数を継承しますが、 優先するものをprocess-environmentで指定できます。 See 節 39.3 オペレーティングシステム環境

Variable: exec-directory
この変数の値は、Emaccsが起動することを意図した GNU Emacsとともに配布されたプログラム群を収めたディレクトリ名 (文字列)である。 プログラムmovemailはそのようなプログラムの例であり、 inboxから新たなメイルを取り出すためにrmailが利用する。

User Option: exec-path
この変数の値は、サブプロセスで実行するプログラムを探索する ディレクトリのリストである。 各要素はディレクトリ名(文字列)であるか、 デフォルトディレクトリ(つまりdefault-directoryの値) を意味するnilである。

引数programが絶対ファイル名でないと、 call-processstart-processexec-pathの値を使う。



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端]

36.2 シェル引数

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp21&node=Shell%20Arguments"
"texi/elisp21/シェル引数"へのコメント(無し)

Lispプログラムから、 ユーザーが指定したファイル名を含んだコマンドを指定して シェルを実行する必要がときどきあります。 これらのプログラムでは、任意の正しいファイル名を扱える必要があります。 しかし、シェルは、特定の文字がファイル名として現れると特別に扱うので、 そのような文字がシェルに混乱をもたらします。 そのような文字を扱うには、関数shell-quote-argumentを使います。

Function: shell-quote-argument argument
この関数は、argumentを実際の内容とする シェル構文で表した引数を文字列で返す。 この戻り値をシェルコマンドに連結し、 実行のためにシェルに渡しても問題を生じないはずである。

この関数が行うことの詳細は読者のオペレーティングシステムに依存する。 この関数は通常のシェル構文に合うように設計してある。 非標準のシェルを使う場合には、この関数を再定義する必要があろう。 MS-DOSでは、この関数はargumentを無変更で返す。 MS-DOSのシェルにはクォートの機能がないため、 これは本当は正しいことではないが最良のことである。

 
;; つぎの例はGNUとUNIXシステムのふるまいである
(shell-quote-argument "foo > bar")
     => "foo\\ \\>\\ bar"

シェルコマンドを作るshell-quote-argumentの使用例をつぎに示す。

 
(concat "diff -c "
        (shell-quote-argument oldfile)
        " "
        (shell-quote-argument newfile))



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端]

36.3 同期プロセスの作成

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp21&node=Synchronous%20Processes"
"texi/elisp21/同期プロセスの作成"へのコメント(無し)

同期プロセス(synchronous process)を作成すると、 Emacsは実行を続行するまえにそのプロセスが終了するのを待ちます。 diredはその例です。 lsを同期プロセスで実行し、その出力を少々修正します。 プロセスは同期なので、Emacsがなにかを行おうとするまえに ディレクトリ一覧全部がバッファに届きます。

Emacsは同期サブプロセスの終了を待ちますが、 ユーザーはC-gと打って中断できます。 C-gはまずシグナルSIGINTでサブプロセスをキルしようとしますが、 中断を完了するまえにサブプロセスが終了するのを待ちます。 その期間にユーザーがさらにC-gを打つと、 SIGKILLでサブプロセスを即座にキルし、ただちに中断を完了します。 See 節 20.9 中断

同期サブプロセス作成関数は、 そのプロセスがどのように終了したかを表すものを返します。

同期サブプロセスからの出力は、ファイルから読むテキストと同様に、 コーディングシステムを用いて一般には復号化します。 call-process-regionがサブプロセスへ送る入力は、 ファイルへ書くテキストと同様に、 コーディングシステムを用いて符号化します。 See 節 32.10 コーディングシステム

Function: call-process program &optional infile destination display &rest args
この関数は、別のプロセスでprogramを呼び出し、 それが終了するのを待つ。

infilenilでなければ プロセスへの標準入力はinfileであるが、 さもなければ`/dev/null'である。 引数destinationでプロセスの出力先をつぎのように指定する。

バッファ
このバッファのポイントのまえに出力を挿入する。 これにはプロセスの標準出力と標準エラーの両者を含む。

文字列
文字列で指定した名前のバッファのポイントのまえに出力を挿入する。

t
カレントバッファのポイントのまえに出力を挿入する。

nil
出力を破棄する。

0
出力を破棄し、サブプロセスの終了を待たずにただちに戻る。

この場合、このプロセスはEmacsと並行して動作するので真のサブプロセスではない。 しかし、この関数から戻るとEmacsはサブプロセスの処理を本質的には終えたと いう意味で同期プロセスと考えることができる。

(real-destination error-destination)
標準出力と標準エラーを分離し、 real-destinationの指定に従って通常の出力を扱い、 error-destinationに従ってエラー出力を処理する。 error-destinationnilであるとエラー出力を破棄し、 tであると通常の出力に混ぜ、 文字列であるとその名前のファイルにエラー出力を振り向ける。

エラー出力を入れるバッファを直接に指定することはできない。 それを実装するのは難しすぎる。 しかし、エラー出力を一時ファイルへ送ってから そのファイルをバッファに挿入すれば、同じ効果を得られる。

displaynil以外であると、call-processは、 出力が挿入されるとバッファを再表示する。 (しかし、コーディングシステムとして実際のデータから コーディングシステムを推定するundecidedを指定していると、 非ASCII文字に出会うと再表示を継続できない場合もある。 これを修正するのが困難である根本的な理由がある。) さもなければ、関数call-processは再表示しないので、 Emacsが通常の過程でそのバッファを再表示するまでは、 スクリーン上で結果は見えない。

残りの引数argsは、プログラムに対する コマンド行引数を指定する文字列である。

(待たないように指示しない限り)call-processが返す値は、 プロセスの終了理由を表す。 数でサブプロセスの終了状態を表し、 0は成功、それ以外の値は失敗を意味する。 プロセスがシグナルで終了すると、 call-processはシグナルを記述する文字列を返す。

つぎの例では、バッファ`foo'がカレントである。

 
(call-process "pwd" nil t)
     => nil

---------- Buffer: foo ----------
/usr/user/lewis/manual
---------- Buffer: foo ----------

(call-process "grep" nil "bar" nil "lewis" "/etc/passwd")
     => nil

---------- Buffer: bar ----------
lewis:5LTsHm66CSWKg:398:21:Bil Lewis:/user/lewis:/bin/csh

---------- Buffer: bar ----------

insert-directoryの定義にあるcall-processの よい使用例をつぎに示す。

 
(call-process insert-directory-program nil t nil switches
              (if full-directory-p
                  (concat (file-name-as-directory file) ".")
                file))

Function: call-process-region start end program &optional delete destination display &rest args
この関数は、programを動かすプロセスの標準入力として startendのあいだのテキストを送る。 deletenil以外であると、送ったテキストを削除する。 これは、カレントバッファに送った入力のかわりに出力を挿入することを 意味するdestinationtであるときに有用である。

引数destinationdisplayは、 サブプロセスからの出力をどのように扱い、 出力か到着するたびに表示を更新するかどうかを制御する。 詳しくは、上記のcall-processの記述を参照。 destinationが整数0であると、 call-process-regionは、サブプロセスの終了を待たずに 出力を破棄してただちにnilを返す。

残りの引数argsは、プログラムに対する コマンド行引数を指定する文字列である。

call-process-regionの戻り値はcall-processと同様であり、 待たずに戻るように指示するとnilであり、 さもなければサブプロセスの終了状態を表す数か文字列である。

つぎの例では、 バッファ`foo'の始めの5文字(単語`input')を標準入力として ユーティリティcatを実行するためにcall-process-regionを使う。 catは、標準入力を標準出力へコピーする。 引数destinationtであるので、 出力はカレントバッファに挿入される。

 
---------- Buffer: foo ----------
input-!-
---------- Buffer: foo ----------

(call-process-region 1 6 "cat" nil t)
     => nil

---------- Buffer: foo ----------
inputinput-!-
---------- Buffer: foo ----------

コマンドshell-command-on-regionは、 つぎのようにcall-process-regionを使う。

 
(call-process-region 
 start end         
 shell-file-name      ; プログラムの名前
 nil                  ; リージョンを削除しない
 buffer               ; 出力はbufferへ入れる
 nil                  ; 出力中は再表示しない
 "-c" command)        ; シェルに対する引数

Function: shell-command-to-string command
この関数は、シェルコマンドとしてcommand(文字列)を実行し、 コマンドの出力を文字列として返す。



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端]

36.4 非同期プロセスの作成

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp21&node=Asynchronous%20Processes"
"texi/elisp21/非同期プロセスの作成"へのコメント(無し)

非同期プロセスを作成すると、Emacsとサブプロセスの両者は ただちに動作を継続します。 そしてプロセスはEmacsと並行に動作し、 両者は以下の節に述べる関数を用いて互いに通信できます。 しかし、通信は部分的に非同期です。 特定の関数を呼び出したときにだけEmacsはプロセスへデータを送り、 Emacsが入力待ちか時間待ちをしているときにだけ プロセスからの出力を受け取れます。

ここでは、非同期プロセスの作成方法について述べます。

Function: start-process name buffer-or-name program &rest args
この関数は、新たな非同期サブプロセスを作成し、 そのプロセスでプログラムprogramを走らせる。 Lispにおいて新たなサブプロセスを表すプロセスオブジェクトを返す。 引数nameはプロセスオブジェクトの名前を指定する。 その名前のプロセスがすでに存在すると、 名前を一意にするために(`<1>'などを付加して)nameを修正する。 バッファbuffer-or-nameは、そのプロセスに対応付けるバッファである。

残りの引数argsは、プログラムに対する コマンド行引数を指定する文字列である。

つぎの例では、最初のプロセスは動き始めると 100秒間(休止ではなく)動作する。 そのあいだに2番目のプロセスを動かし始めると、 一意であるためにそれには名前`my-process<1>'が与えられる。 2番目のプロセスは、最初のプロセスが終了するまえに バッファ`foo'にディレクトリ一覧を挿入する。 2番目のプロセスが終了するとそれを表すメッセージがバッファに挿入される。 しばらくして最初のプロセスが終了すると、 別のメッセージがバッファに挿入される。

 
(start-process "my-process" "foo" "sleep" "100")
     => #

(start-process "my-process" "foo" "ls" "-l" "/user/lewis/bin")
     => #>

---------- Buffer: foo ----------
total 2
lrwxrwxrwx  1 lewis     14 Jul 22 10:12 gnuemacs --> /emacs
-rwxrwxrwx  1 lewis     19 Jul 30 21:02 lemon

Process my-process<1> finished

Process my-process finished
---------- Buffer: foo ----------

Function: start-process-shell-command name buffer-or-name command &rest command-args
この関数はstart-processと同様であるが、 指定したコマンドを実行するためにシェルを用いる点が異なる。 引数commandはシェルコマンドの名前であり、 command-argsはそのシェルコマンドに対する引数である。 変数shell-file-nameは、使用するシェルを指定する。

start-processで直接にではなく シェルを介してプログラムを実行すると、 引数のワイルドカードなどのシェルの機能を利用できる。 つまり、ユーザー指定の任意のファイル名をコマンドに入れる場合には、 まえもってshell-quote-argumentでクォートし、 ファイル名内のシェルの特別な文字が そのような特別な意味を持たないようにする。 see 節 36.2 シェル引数

Variable: process-connection-type
この変数は、非同期サブプロセスとの通信に用いる装置の型を制御する。 これがnil以外であると疑似端末PTYを利用できる場合にはそれを用る。 さもなければパイプを用いる。

シェル(shell)モードなどのユーザーに見えるプロセス向けには、 パイプでは不可能なプロセスとその子プロセスとのあいだで ジョブ制御(C-cC-zなど)を許すので 疑似端末PTYが望ましい。 プログラムの内部目的向けに使われるサブプロセスでは、 効率的なパイプを用いるほうがよい。 また、多くのシステムでは疑似端末PTYの総数には制約があり、 それらを浪費しないほうがよい。

process-connection-typeの値は start-processを呼び出したときに使われる。 したがって、start-processの呼び出しの周りでこの変数を束縛することで、 1つのサブプロセスに対する通信方法を指定できる。

 
(let ((process-connection-type nil))  ; パイプを使う
  (start-process ...))

サブプロセスが実際にはパイプか疑似端末PTYのどちらを 使っているかを調べるには、関数process-tty-nameを使う (see 節 36.6 プロセス情報)。



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端]

36.5 プロセスの削除

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp21&node=Deleting%20Processes"
"texi/elisp21/プロセスの削除"へのコメント(無し)

プロセスを削除するとは、サブプロセスからEmacsをただちに切り離し、 サブプロセスを活性なプロセスリストから取り除くことです。 サブプロセスへシグナルを送ってサブプロセスを終了させますが、 ただちに終了するとは保証されません。 プロセスオブジェクトを指すLispオブジェクトがある限り、 プロセスオブジェクトは存在し続けます。 プロセスマークは以前と同様に同じ場所 (プロセスからの出力をバッファに挿入した箇所)を指し続けます。

プロセスはいつでも明示的に削除できます。 プロセスは終了後に自動的に削除されますが、 終了後ただちにではありません。 終了したプロセスが自動的に削除されるまえに明示的に削除しても無害です。

User Option: delete-exited-processes
この変数は、(exitを呼び出すかシグナルのために)終了した プロセスの自動削除を制御する。 nilであると、ユーザーがlist-processesを 実行するまで存在し続ける。 さもなければ、終了後にただちに削除する。

Function: delete-process name
この関数は、nameに対応付けられたプロセスを シグナルSIGHUPでキルし削除する。 引数は、プロセス、プロセス名、バッファ、バッファ名のいずれかである。

 
(delete-process "*shell*")
     => nil

Function: process-kill-without-query process &optional do-query
この関数は、Emacsを終了するときにプロセスprocessが動作中であると、 ユーザーに問い合わせるかどうかを指定する。 do-querynilであると、プロセスを黙って削除する。 さもなければ、Emacsはプロセスのキルに関して問い合わせる。

問い合わせるようにしてあったプロセスであると戻り値はtであり、 さもなければ戻り値はnilである。 新たに作成されたプロセスは、つねに問い合わせ用になっている。

 
(process-kill-without-query (get-process "shell"))
     => t



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端]

36.6 プロセス情報

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp21&node=Process%20Information"
"texi/elisp21/プロセス情報"へのコメント(無し)

プロセスに関する情報を返す関数がいくつかあります。 list-processesは対話的利用のためにあります。

コマンド: list-processes
このコマンドは、活性なすべてのプロセスの一覧を表示する。 さらに、`Exited'や`Signaled'である状態の プロセスをすべて削除する。 nilを返す。

Function: process-list
この関数は、削除されていないすべてのプロセスのリストを返す。

 
(process-list)
     => (# #)

Function: get-process name
この関数はnameという名前のプロセスを返す。 あるいは、そのようなプロセスがなければnilを返す。 nameが文字列でないとエラーを通知する。

 
(get-process "shell")
     => #

Function: process-command process
この関数は、プロセスprocessを始動するために実行したコマンドを返す。 これは文字列のリストであり、 最初の文字列は実行されたプログラム、 残りの文字列はそのプログラムに与えた引数である。

 
(process-command (get-process "shell"))
     => ("/bin/csh" "-i")

Function: process-id process
この関数は、プロセスprocessのプロセス番号PIDを返す。 これは同じ計算機上で動いている他のすべてのプロセスと プロセスprocessを区別するための整数である。 プロセスのPIDは、プロセスを始動したときに オペレーティングシステムのカーネルが選び、 プロセスが終了するまで変わらない。

Function: process-name process
この関数はプロセスprocessの名前を返す。

Function: process-contact process
この関数は、通常の子プロセスに対してはtを返し、 ネットワーク接続に対しては(hostname service)を返す (see 節 36.12 ネットワーク接続)。

Function: process-status process-name
この関数は、process-nameの状態をシンボルとして返す。 引数process-nameは、プロセス、バッファ、プロセス名(文字列)、 バッファ名(文字列)のいずれかであること。

実際のサブプロセスに対して可能な値はつぎのとおり。

run
実行中のプロセスである。
stop
一時停止しているが継続可能である。
exit
終了したプロセス。
signal
致命的なシグナルを受け取ったプロセスである。
open
ネットワーク接続を開いている。
closed
ネットワーク接続は閉じている。 接続をいったん閉じるとそれを再度開くことはできないが、 同じ接続先へ新たな接続を開くことはできる。
nil
process-nameは既存プロセスの名前ではない。

 
(process-status "shell")
     => run
(process-status (get-buffer "*shell*"))
     => run
x
     => #>
(process-status x)
     => exit

ネットワーク接続では、process-statusは シンボルopenclosedのいずれかを返す。 後者は、相手側が接続を閉じたか Emacsがdelete-processを行ったことを表す。

Function: process-exit-status process
この関数は、プロセスprocessの終了状態か、 プロセスをキルしたシグナル番号を返す。 (どちらであるかを判定するには、process-statusの結果を用いる。) processが終了していないと値は0である。

Function: process-tty-name process
この関数は、プロセスprocessがEmacsとの通信に用いている端末名を返す。 あるいは、端末のかわりにパイプを用いていればnilを返す (36.4 非同期プロセスの作成process-connection-typeを参照)。

Function: process-coding-system process
この関数は、プロセスprocessからの出力を 復号化するために用いているコーディングシステムと、 processへの入力を符号化するために用いている コーディングシステムを記述するコンスセルを返す。

 
(coding-system-for-decoding . coding-system-for-encoding)

Function: set-process-coding-system process decoding-system encoding-system
この関数は、プロセスprocessからの以降の出力および入力に用いる コーディングシステムを指定する。 サブプロセスから出力の復号化にはdecoding-systemを使い、 サブプロセスの入力の符号化にはencoding-systemを使う。



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端]

36.7 プロセスへ入力を送る

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp21&node=Input%20to%20Processes"
"texi/elisp21/プロセスへ入力を送る"へのコメント(無し)

本節の関数を用いてEmacsが入力を送ると、 非同期プロセスは入力を受け取ります。 入力の送先であるプロセスと、送るべき入力データを指定する必要があります。 そのデータは、サブプロセスの『標準入力』に現れます。

疑似端末PTYのバッファ付き入力の容量に上限がある オペレーティングシステムもあります。 そのようなシステムでは、Emacsは他の文字に混ぜて定期的にEOFを送り、 文字が流れるように強制します。 ほとんどのプログラムでは、このようなEOFは無害なはずです。

ファイルに書き込むテキストと同様に、 サブプロセスの入力は、サブプロセスがそれを受け取るまえに コーディングシステムを用いて普通は符号化されます。 set-process-coding-systemで 使用するコーディングシステムを指定できます (see 節 36.6 プロセス情報)。 さもなければ、coding-system-for-writenil以外であればこれを使います。 それ以外ではデフォルトの機構で決まるものを使います (see 節 32.10.5 デフォルトのコーディングシステム)。

Function: process-send-string process-name string
この関数は、文字列stringの内容を 標準入力としてプロセスprocess-nameに送る。 引数process-nameは、プロセスかプロセス名であること。 これがnilであると、カレントバッファのプロセスを用いる。

関数はnilを返す。

 
(process-send-string "shell<1>" "ls\n")
     => nil


---------- Buffer: *shell* ----------
...
introduction.texi               syntax-tables.texi~
introduction.texi~              text.texi
introduction.txt                text.texi~
...
---------- Buffer: *shell* ----------

コマンド: process-send-region process-name start end
この関数は、startendで定義される領域内のテキストを 標準入力としてプロセスprocess-nameへ送る。 process-nameはプロセスかプロセス名であること。 (nilであると、カレントバッファのプロセスを使う。)

startendのどちらかが カレントバッファ内の位置を表す整数でもマーカでもないと、 エラーを通知する。 (どちらが大きな数であるかは重要ではない。)

Function: process-send-eof &optional process-name
この関数は、プロセスprocess-nameが入力で 「ファイルの終りEOF」を見るようにする。 EOFはそれまでに送ったテキストのあとにある。

process-nameを指定しなかったりnilであると、 この関数はカレントバッファのプロセスにEOFを送る。 カレントバッファにプロセスがないとエラーを通知する。

関数はprocess-nameを返す。

 
(process-send-eof "shell")
     => "shell"



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端]

36.8 プロセスにシグナルを送る

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp21&node=Signals%20to%20Processes"
"texi/elisp21/プロセスにシグナルを送る"へのコメント(無し)

サブプロセスにシグナルを送ることは、 サブプロセスの動作に割り込む一方法です。 それぞれ独自の意味を持つ異なるシグナルがいくつかあります。 一連のシグナルとそれらの名前は、オペレーティングシステムが定義します。 たとえば、シグナルSIGINTは、ユーザーがC-cを打った、 あるいは、それと同様なことが起こったことを意味します。

各シグナルには、サブプロセスに対する標準的な効果があります。 ほとんどのシグナルはサブプロセスをキルしますが、 その実行を一時停止したり再開するものもあります。 プログラムがシグナルを処理している場合には、 シグナルの効果を一般的に述べることはできません。

本節の関数を呼び出してシグナルを明示的に送ることができます。 また、Emacsは特定の場面で自動的にシグナルを送ります。 バッファを削除すると、そのバッファに対応付けられているすべての プロセスにシグナルSIGHUPを送ります。 Emacsを終了するときには、動作しているすべてのサブプロセスに シグナルSIGHUPを送ります。 (SIGHUPは、ユーザーが電話を切ったことを普通は表すシグナル。)

シグナルを送る各関数は、省略可能な2つの引数、 process-namecurrent-groupを受け付けます。

引数process-nameは、プロセス、プロセス名、nilのいずれかです。 これがnilであると、カレントバッファに対応付けられているプロセスが デフォルトになります。 process-nameがプロセスを指定しないとエラーを通知します。

引数current-groupは、Emacsのサブプロセスとして ジョブ制御可能なシェルを実行しているときに違いが現れるフラグです。 これがnil以外であると、 Emacsがサブプロセスとの通信に用いている端末の現在のプロセスグループに シグナルを送ります。 プロセスがジョブ制御可能なシェルであると、 これはシェルの現在のサブジョブ (10) であることを意味します。 nilであると、Emacsのサブプロセスの直接のプロセスグループに シグナルを送ります。 プロセスがジョブ制御可能なシェルであると、これはシェルそのものです。

オペレーティングシステムはパイプではプロセスグループを扱わないため、 サブプロセスとの通信にパイプを用いている場合には、 フラグcurrent-groupには効果はありません。 同じ理由で、パイプを用いている場合には ジョブ制御可能なシェル(のジョブ制御機能)は働きません。 36.4 非同期プロセスの作成process-connection-typeを参照してください。

Function: interrupt-process &optional process-name current-group
この関数は、プロセスprocess-nameに シグナルSIGINTを送って割り込む。 Emacsの外側では、『割り込み文字』(普通、C-cであるシステムもあり、 その他のシステムではDEL)を打つとこのシグナルを送る。 引数current-groupnil以外であると、 この関数は、Emacsがサブプロセスと通信している端末上で 『C-cを打つ』と考えることができる。

Function: kill-process &optional process-name current-group
この関数は、プロセスprocess-nameに シグナルSIGKILLを送ってキルする。 このシグナルはサブプロセスを即座にキルし、 サブプロセスはこれを処理できない。

Function: quit-process &optional process-name current-group
この関数は、プロセスprocess-nameにシグナルSIGQUITを送る。 このシグナルは、『中断文字』 (Emacsの外側では普通はC-bC-\)が 送るシグナルと同じものである。

Function: stop-process &optional process-name current-group
この関数は、プロセスprocess-nameに シグナルSIGTSTPを送って一時停止させる。 その実行を再開させるにはcontinue-processを使う。

Emacsの外側でジョブ制御可能なシステムでは、 『一時停止文字』(普通はC-z)が普通はこのシグナルを送る。 current-groupnil以外であると、 この関数は、Emacsがサブプロセスと通信している端末上で 『C-zを打つ』と考えることができる。

Function: continue-process &optional process-name current-group
この関数は、プロセスprocessに シグナルSIGTCONTを送って実行を再開させる。 以前に一時停止させられたprocessを再開する。

Function: signal-process pid signal
この関数は、必ずしもEmacsの子プロセスではない プロセスpidにシグナルを送る。 引数signalは、送るべきシグナルを整数で指定する。



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端]

36.9 プロセスからの出力を受け取る

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp21&node=Output%20from%20Processes"
"texi/elisp21/プロセスからの出力を受け取る"へのコメント(無し)

サブプロセスが標準出力に書く出力を受け取る方法は2つあります。 プロセスに対応付けられたバッファに出力を挿入するか、 あるいは、フィルタ関数(filter function)と呼ばれる関数を 出力に対して作用させます。 プロセスにバッファもフィルタ関数もなければ、その出力は破棄します。

サブプロセスからの出力は、Emacsが待っている、つまり、 端末入力を読んでいるとき、 sit-forsleep-forを実行中のとき(see 節 20.8 時間待ちと入力待ち)、 accept-process-output(see 節 36.9.3 プロセスからの出力を受け取る)を実行中のときに だけ到着します。 これにより、並行プログラムを普通は悩ますような タイミングエラーの問題を最小に抑えます。 たとえば、安全にプロセスを作成してから、 バッファかフィルタ関数を指定できます。 この処理の途中で待つような基本関数を呼び出さなければ、 出力は到着しません。

ファイルから読むテキストと同様に、 サブプロセスの出力は、バッファやフィルタ関数が受け取るまえに コーディングシステムを用いて普通は復号化します。 set-process-coding-systemで 使用するコーディングシステムを指定できます (see 節 36.6 プロセス情報)。 さもなければ、coding-system-for-readnil以外であればこれを使います。 それ以外ではデフォルトの機構で決まるものを使います (see 節 32.10.5 デフォルトのコーディングシステム)。

警告: データからコーディングシステムを決定するundecidedのような コーディングシステムは、非同期サブプロセスの出力に対しては 完全に信頼性のある動作はできない。 これは、Emacsが非同期サブプロセスの出力が 到着するたびに一塊で処理するからである。 Emacsは1つの塊から正しい変換を検出しようと試みるが、 これがつねに動作するとは限らない。 したがって、可能な限り 文字コード変換と行末変換の両方を指定したコーディングシステムを使う。 つまり、undecidedlatin-1などではなく、 latin-1-unixのようなものを使う。

36.9.1 プロセスバッファ    If no filter, output is put in a buffer.
36.9.2 プロセスフィルタ関数    Filter functions accept output from the process.
36.9.3 プロセスからの出力を受け取る    Explicitly permitting subprocess output. Waiting for subprocess output.



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端]

36.9.1 プロセスバッファ

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp21&node=Process%20Buffers"
"texi/elisp21/プロセスバッファ"へのコメント(無し)

プロセスには対応付けられたバッファが(普通は)あります。 そのバッファはEmacsの普通のバッファであり、2つの目的に使われます。 プロセスからの出力を保存することと、 プロセスがキルされたことを判定するためです。 バッファを用いてそれを操作しているプロセスを識別することもできます。 普通は1つのバッファに1つのプロセスを対応付けるからです。 プロセスの多くの応用では、プロセスへ送る入力を編集するために バッファを使いますが、これはEmacs Lispに組み込まれたことではありません。

プロセスにフィルタ関数(see 節 36.9.2 プロセスフィルタ関数)がなければ、 その出力は対応付けられたバッファに挿入されます。 出力の挿入位置はprocess-markで決定され、 process-markは挿入したばかりのテキストの末尾を 指すように更新されます。 process-markは普通はバッファの末尾にありますが、 つねにそうであるとは限りません。

Function: process-buffer process
この関数は、プロセスprocessに対応付けられているバッファを返す。

 
(process-buffer (get-process "shell"))
     => #

Function: process-mark process
この関数は、プロセスprocessからの出力を挿入する箇所を指定する processのプロセスマーカを返す。

processにバッファがなければ、 process-markはどこも指していないマーカである。

バッファにプロセス出力を挿入する際には、 挿入箇所を決定するためにこのマーカを使用し、 挿入したテキストの末尾を指すようにこのマーカを更新する。 これにより、出力の連続した塊を順に挿入できるのである。

バッファに出力を直接挿入する場合と同様に、 フィルタ関数はこのマーカを扱うべきである。 process-markを用いたフィルタ関数の好例は、以下の節にある。

プロセスへ送るためにユーザーがプロセスバッファに 入力することが予想されるときは、 プロセスマーカは新たな入力とそれ以前の出力を区切る。

Function: set-process-buffer process buffer
この関数は、プロセスprocessにバッファbufferを対応付ける。 buffernilであると、 プロセスに対応付けられたバッファはない。

Function: get-buffer-process buffer-or-name
この関数はbuffer-or-nameに対応付けられたプロセスを返す。 バッファに複数のプロセスが対応付けられている場合には、 それらの1つを選ぶ。 (現状では、もっとも最近に作られたプロセスを選ぶ。) 同じバッファに複数のプロセスを対応付けることは一般にはよくない。

 
(get-buffer-process "*shell*")
     => #

プロセスのバッファを削除すると、 サブプロセスにシグナルSIGHUPを送ってプロセスを削除する (see 節 36.8 プロセスにシグナルを送る)。



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端]

36.9.2 プロセスフィルタ関数

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp21&node=Filter%20Functions"
"texi/elisp21/プロセスフィルタ関数"へのコメント(無し)

プロセスのフィルタ関数(filter function)は、 対応付けられたプロセスからの標準出力を受け取る関数です。 プロセスにフィルタがあると、そのプロセスからのすべての出力は フィルタに渡されます。 プロセスにフィルタがない場合に限って、 プロセスからの出力向けにプロセスバッファを直接使います。

フィルタ関数は、Emacsがなにかを待っているときにのみ呼ばれます。 そのような期間にのみプロセスの出力が到着するからです。 Emacsが待つのは、端末入力を読んでいるとき、 sit-forsleep-forを実行中のとき(see 節 20.8 時間待ちと入力待ち)、 accept-process-output(see 節 36.9.3 プロセスからの出力を受け取る)を実行中のときです。

フィルタ関数は2つの引数、 対応付けられたプロセスとそのプロセスから受け取ったばかりの出力である文字列を 受け取ります。 関数は出力に対してなにを行ってもかまいません。

フィルタ関数の内側では中断は普通は禁止されています。 さもないと、コマンドレベルで打ったC-gの効果や、 ユーザーコマンドを中断するために打ったC-gの効果は予測できません。 フィルタ関数の内側で中断を行いたい場合には、 inhibit-quitnilを束縛します。 See 節 20.9 中断

フィルタ関数の実行中にエラーが発生するとそのエラーは自動的に捕捉され、 フィルタ関数を始動したときに動いていた プログラムの実行を停止しないようにします。 しかし、debug-on-errornil以外であると、 エラーを捕捉しません。 これにより、Lispデバッガでフィルタ関数をデバッグできます。 See 節 17.1 Lispデバッガ。

多くのフィルタ関数は、ときどきあるいはつねに、 プロセスのバッファにテキストを挿入します。 これはフィルタ関数がないときのEmacsの動作を模倣するものです。 そのようなフィルタ関数では、対象のバッファに挿入するために set-bufferを使う必要があります。 カレントバッファをなかば恒久的に切り替えないように、 これらのフィルタ関数はカレントバッファを記録/復元する必要があります。 プロセスマーカを更新し、必要に応じてポイントの値も更新します。 これらはつぎのように行います。

 
(defun ordinary-insertion-filter (proc string)
  (with-current-buffer (process-buffer proc)
    (let ((moving (= (point) (process-mark proc))))
      (save-excursion
        ;; テキストを挿入し、プロセスマーカを進める
        (goto-char (process-mark proc))
        (insert string)
        (set-marker (process-mark proc) (point)))
      (if moving (goto-char (process-mark proc))))))

カレントバッファを記録/復元するためにsave-excursionではなく with-current-bufferを使うのは、 2番目のgoto-charの呼び出しで行うポイントの移動効果を 有効にするためです。

新たにテキストが到着するたびにプロセスバッファが見えるように フィルタ関数で強制するには、 つぎのような行をwith-current-bufferの直前に入れます。

 
(display-buffer (process-buffer proc))

ポイント位置に関わらずに新たな出力の末尾にポイントを移動するには、 変数movingを削除して、 無条件にgoto-charを呼び出します。

Emacsの初期の版では、正規表現を探索したり一致処理するフィルタ関数では、 マッチデータを明示的に保存/復元する必要がありました。 今のEmacsは、フィルタ関数に対してはこれを自動的に行いますから、 フィルタ関数で明示的に行う必要はありません。 See 節 33.6 マッチデータ。

プロセスのバッファに出力を書き込むフィルタ関数は、 そのバッファが有効であるかどうかを検査するべきです。 無効なバッファに挿入しようとするとエラーになります。 バッファが無効であれば、 式(buffer-name (process-buffer process)) を実行するとnilを返します。

関数に渡される出力は任意のサイズの塊できます。 同じ出力を2回生成するプログラムは、 あるときには一度に200文字の塊を1つ送る場合もあれば、 40文字の塊を5つ送る場合もあります。 サブプロセスの出力から特定のテキスト文字列を探すフィルタでは、 そのような文字列が2つかそれ以上の出力の塊に分割される場合も 扱えるようにします。

Function: set-process-filter process filter
この関数は、プロセスprocessにフィルタ関数filterを指定する。 filternilであると、プロセスにフィルタはない。

Function: process-filter process
この関数は、プロセスprocessのフィルタ関数を返す。 あるいは、フィルタ関数がなければnilを返す。

フィルタ関数の使用例をつぎに示します。

 
(defun keep-output (process output)
   (setq kept (cons output kept)))
     => keep-output
(setq kept nil)
     => nil
(set-process-filter (get-process "shell") 'keep-output)
     => keep-output
(process-send-string "shell" "ls ~/other\n")
     => nil
kept
     => ("lewis@slug[8] % "
"FINAL-W87-SHORT.MSS    backup.otl              kolstad.mss~
address.txt             backup.psf              kolstad.psf
backup.bib~             david.mss               resume-Dec-86.mss~
backup.err              david.psf               resume-Dec.psf
backup.mss              dland                   syllabus.mss
"
"#backups.mss#          backup.mss~             kolstad.mss
")



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端]

36.9.3 プロセスからの出力を受け取る

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp21&node=Accepting%20Output"
"texi/elisp21/プロセスからの出力を受け取る"へのコメント(無し)

非同期サブプロセスからの出力は、 Emacsが時間待ちや端末入力などの なんらかの外部事象を待っているときにのみ到着します。 Lispプログラムから特定の場面で出力の到着を明示的に許したり、 プロセスの出力が到着するのを待つことができると有用なことがあります。

Function: accept-process-output &optional process seconds millisec
この関数は、Emacsにプロセスからの未処理の出力を読み取ることを許す。 その出力は、対応付けられたバッファに挿入されるか、 フィルタ関数に与えられる。 processnil以外であると、 この関数は、processからなんらかの出力を得るまで戻らない。

引数secondsmillisecは、時間切れを指定する。 前者は秒単位の時間、後者はミリ秒単位の時間を指定する。 指定された2つの時間は合計され、 任意のサブプロセスの出力を受け取ったどうかに関わらず、 その時間だけ経過するとaccept-process-outputは戻ってくる。

引数secondsは整数である必要はない。 浮動小数点数であると、この関数は秒未満の時間も待つ。 秒未満を扱えないシステムもある。 そのようなシステムでは、secondsを切り下げる。

すべてのオペレーティングシステムで秒未満を扱えるわけではない。 扱えないシステムでmillisecにゼロ以外を指定すると エラーになる。

関数accept-process-outputは、 出力を得るとnil以外を返す。 あるいは、出力が到着するまえに時間切れするとnilを返す。



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端]

36.10 番兵:プロセスの状態変化の検出

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp21&node=Sentinels"
"texi/elisp21/番兵:プロセスの状態変化の検出"へのコメント(無し)

プロセスの番兵(process sentinel)は、 プロセスを終了/一時停止/継続させる (Emacsが送ったかプロセス自身の動作によって生起した)シグナルを含めて 対応付けられたプロセスの状態が任意の理由で変化したときに 呼び出される関数です。 プロセスの番兵は、プロセスが終了しても呼び出されます。 番兵は2つの引数、事象が発生したプロセスと 事象の種類を記述する文字列を受け取ります。

事象を記述する文字列はつぎのとおりです。

番兵はEmacsが(たとえば、端末入力や時間経過、プロセスの出力を) 待っているときにのみ実行されます。 他のLispプログラムの実行途中で無秩序に番兵を実行した場合に起こる タイミングエラーを回避するためです。 sit-forsleep-for(see 節 20.8 時間待ちと入力待ち)、あるいは、 accept-process-output(see 節 36.9.3 プロセスからの出力を受け取る)を 呼び出すとプログラムは待ちに入り、番兵が動けることになります。 Emacsは、コマンドループで入力を読むときにも番兵の実行を許します。

番兵の内側では中断は普通は禁止されています。 さもないと、コマンドレベルで打ったC-gの効果や、 ユーザーコマンドを中断するために打ったC-gの効果は予測できません。 番兵の内側で中断を行いたい場合には、 inhibit-quitnilを束縛します。 See 節 20.9 中断

プロセスのバッファに出力を書き込む番兵は、 そのバッファが有効であるかどうかを検査するべきです。 無効なバッファに挿入しようとするとエラーになります。 バッファが無効であれば、 式(buffer-name (process-buffer process)) を実行するとnilを返します。

番兵の実行中にエラーが発生するとそのエラーは自動的に捕捉され、 番兵を始動したときに動いていた プログラムの実行を停止しないようにします。 しかし、debug-on-errornil以外であると、 エラーを捕捉しません。 これにより、Lispデバッガで番兵をデバッグできます。 See 節 17.1 Lispデバッガ。

Emacsの初期の版では、正規表現を探索したり一致処理する番兵では、 マッチデータを明示的に保存/復元する必要がありました。 今のEmacsは、番兵に対してはこれを自動的に行いますから、 番兵で明示的に行う必要はありません。 See 節 33.6 マッチデータ。

Function: set-process-sentinel process sentinel
この関数は、プロセスprocessに番兵sentinelを対応付ける。 sentinelnilであると、プロセスに番兵はない。 番兵がない場合のデフォルトのふるまいは、 プロセス状態が変化するとプロセスのバッファにメッセージを挿入する。

 
(defun msg-me (process event)
   (princ
     (format "Process: %s had the event `%s'" process event)))
(set-process-sentinel (get-process "shell") 'msg-me)
     => msg-me
(kill-process (get-process "shell"))
     -| Process: # had the event `killed'
     => #

Function: process-sentinel process
この関数は、プロセスprocessの番兵を返すか、 番兵がなければnilを返す。

Function: waiting-for-user-input-p
番兵やフィルタ関数が動作中にこの関数を呼び出すと、 番兵やフィルタ関数を呼び出したときにEmacsがユーザーからの キーボード入力を待ってるとnil以外を返し、 それ以外ではnilを返す。



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端]

36.11 トランザクションキュー

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp21&node=Transaction%20Queues"
"texi/elisp21/トランザクションキュー"へのコメント(無し)

トランザクションを用いたサブプロセスとの通信に トランザクションキュー(transaction queue)を使えます。 まずtq-createを用いて、 指定したプロセスとの通信用トランザクションキューを作成します。 そして、トランザクションを送るためにtq-enqueueを呼び出します。

Function: tq-create process
この関数は、プロセスprocessとの通信用トランザクションキューを 作成して返す。 引数processは、バイトストリームを送受信できる機能を 有するサブプロセスであること。 つまり、子プロセスであるか、別のマシン上の可能性もある サーバーへのTCP接続である。

Function: tq-enqueue queue question regexp closure fn
この関数はキューqueueにトランザクションを送る。 キューを指定することは、 通信相手のサブプロセスを指定する効果がある。

引数questionは、トランザクションを始める送出メッセージである。 引数fnは、対応する応答が戻ってきたときに呼び出す関数である。 その関数は2つの引数、closureと受け取った応答で呼び出される。

引数regexpは、1つの応答だけに一致する正規表現である。 tq-enqueueが応答の末尾を判定するために使う。

tq-enqueueの戻り値そのものに意味はない。

Function: tq-close queue
未処理のトランザクションすべてが完了するのを待ち、 接続や子プロセスを終了して、 トランザクションキューqueueを終える。

トランザクションキューはフィルタ関数を用いて実装してあります。 See 節 36.9.2 プロセスフィルタ関数



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端]

36.12 ネットワーク接続

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp21&node=Network"
"texi/elisp21/ネットワーク接続"へのコメント(無し)

Emacs Lispプログラムは、同一マシンや別のマシン上の他のプロセスに対して TCPネットワーク接続を開くことができます。 ネットワーク接続は、サブプロセスと同様にLispが扱い、 プロセスオブジェクトとして表現されます。 しかし、通信相手のプロセスはEmacsプロセスの子プロセスではありませんから、 キルしたりシグナルを送ることはできません。 データの送受信のみが可能です。 delete-processは接続を閉じますが、 もう一方の端のプロセスをキルしません。 そのプロセスは、接続が閉じた場合の動作を判断する必要があります。

ネットワーク接続を表すプロセスオブジェクトと サブプロセスを表すプロセスオブジェクトとは、 関数process-statusを使って区別できます。 この関数は、ネットワーク接続に対しては openclosedをつねに返し、 本当のサブプロセスに対してはこれらのいずれの値もけっして返しません。 See 節 36.6 プロセス情報

Function: open-network-stream name buffer-or-name host service
この関数は、ホストのサーバーに対するTCP接続を開く。 接続を表すプロセスオブジェクトを返す。

引数nameは、プロセスオブジェクトに付ける名前を指定する。 必要に応じて一意にするために修正される。

引数buffer-or-nameは、接続に対応付けるバッファである。 出力を扱うフィルタ関数を指定しない限り、 接続からの出力はそのバッファに挿入される。 buffer-or-namenilであると、 接続にはバッファを対応付けないことを意味する。

引数hostserviceは、接続先を指定する。 hostはホスト名(文字列)であり、 serviceは定義済みのネットワークサービス(文字列)か ポート番号(整数)である。


[ << ] [ >> ]           [表紙] [目次] [索引] [検索] [上端 / 下端]