UNIX/Linuxの部屋 コマンド:exec


※空白区切りで AND 検索 (例:「ファイル 削除」)

コマンド exec 現在実行中のシェルに代わり、指定したコマンドを実行する

シェルから
% ls
とコマンドを実行すると、シェルは以下のことを行う。
  • システムコール fork(2) を呼び、子プロセスを生成する。
  • 子プロセスは ls を exec(2) する。
  • 親プロセスであるシェルは、ls の実行が完了するのを待つ (wait する)。

一方、
% exec ls
と exec を使うと、シェルは fork(2) せず、いきなり ls コマンドを exec(2) する (シェルの内部コマンド exec(1) を実行すると、内部でシステムコール exec(2) が呼ばれるということ)。シェルのプロセス情報は ls のプロセスの情報で上書きされる。なお、子プロセスは生成されないので、シェルと ls のプロセス ID は同じになる。

実際にやってみるとわかるが、kterm などの端末エミュレータ上でシェルを動かしているときに
% exec ls
とすると一瞬 ls の結果が実行されるが、kterm は終了してしまう (kterm は通常シェルが終わるのを待っているが、シェルのプロセスは ls のプロセスに上書きされるので、ls が終了すると kterm も終了してしまう)。

exec のつかいどころは以下のとおり。

例 1. ~/.xinitrc や ~/.xsession
~/.xinitrc や ~/.xsession では、通常 kterm などの端末エミュレータを数個呼び、twm や fvwm などのウィンドウマネージャを起動する。ここで
#!/bin/sh
kterm -g 102x60+10+10 &
kterm -g 90x52-10-10 &
twm
ではなく、
#!/bin/sh
kterm -g 102x60+10+10 &
kterm -g 90x52-10-10 &
exec twm # ここで exec を使う
と書くとよい。前者は twm を実行している間 (≒ユーザがログインしている間)、sh がずっと twm の終了を待っている。しかし後者は sh のプロセスは twm のプロセスで上書きされてしまうので、前者よりプロセス数が一つ少なくてすむ。

例 2. wrapper スクリプト
例えば FreeBSD 4.7-RELEASE の /usr/bin/pagesize。中身は以下のような sh スクリプトで、sysctl を実行するだけの wrapper スクリプトである。
#!/bin/sh -
PATH=/bin:/usr/bin:/sbin:/usr/sbin; export PATH
exec sysctl -n hw.pagesize
これも sysctl を実行する間、/bin/sh を待たせなくてよいという効果がある。

同様に、FreeBSD 4.7-RELEASE で調べてみると、
  • /usr/bin/clear は tput を exec する
  • /usr/bin/sockstat は netstat を exec する
  • /usr/bin/perldoc は perl を exec する
  • gs 付属のプログラム (pf2afm、ps2pdf など) は gs を exec する
などなど、多くの wrapper スクリプトが exec でコマンドを呼んでいる。

まとめ
exec による効果は以下の通り。
  • fork(2) で子プロセスを生成しなくてすむ。fork(2) はかなり重いシステムコールである。fork(2) が重いので、vfork(2) が作られたくらい重い。ただ、現代の UNIX では copy-on-write の効果により、以前ほど fork(2) が重いわけではない。
  • 親プロセスが子プロセスの終了を待つ必要がない。1 プロセス分浮くわけである。

exec を 1回使うことによる速度向上・メモリ量削減効果はたいしたことはない。ただし数百回・数千回分続くようなら、塵も積もれば…となる。例えば大学のような「1つの大型サーバと数十台の X 端末」という状況で、上記の例 1 を考えると、
twm
の部分を
exec twm
とするだけで、一気に数十プロセスが浮くわけである。

関数 exec コマンドを実行

exec 系のライブラリ関数には
execl
execle
execlp
exect
execv
execvp
execvP
がある。これらは最終的にシステムコール execve(2) を呼び出す。


頑張って書いたおすすめコンテンツ!
クラウドサービス徹底比較・徹底解説