プロセスとジョブ

これまで、コマンドを実行するという話しかして来ませんでしたが、 UNIXでは実行されるコマンド(プログラム)の単位をプロセスと呼びます。

というだけだと、ここで書くことはほとんど無いのですが。 UNIXにはいくつかのプロセスを組み合わせて仕事をすることができます。 このとき組み合わされたプロセスの集合体のことをジョブと呼びます。

コマンドの組み合わせ方としては、連続実行・バックグラウンドで実行・ パイプで連結という方法があります。 その他に、コマンドの実行結果で置き換えるコマンド置換があります。 以下順に説明していきます。

連続実行:";"

コマンドを連続して実行するためには ";"を利用します。 やってみましょう。

	   >   wc /kernel;ls -l
	  3757   46638 1232945 /kernel
	  total 2
	  -rw-r--r--   1 mutoh    mutoh       107 Jul 11 17:18 memo.bak
	  -rw-r--r--   1 mutoh    mutoh        63 Jul 12 09:59 memo.kanji
	

/kernelというのは、UNIXの本体です。 結構大きいので、wcが数えるのも大変です。

入力後、しばらくしてwcの結果と ls -lの結果が出て来ました ね? 順番も、wcの結果のあとに ls -lの結果となっています。 今見たように、";"は、かかれた順番にコマンドを実行していきます。

バックグラウンド実行:"&"

こんどは、バックグラウンドの実行です。 "バックグラウンドでの実行をする"とはどういうことでしょうか?

UNIXははじめに話したようなマルチタスクのOSです。 マルチタスクのOSでは、 いろいろなコマンドを同時に動かすことができるのです [1] 。 では、やってみましょう。

	   >   yes > /dev/null &
	  [1] 24630
	

コマンドをいれるなり、プロンプトが帰って来ましたね? ここではじめて出てきたyesは、yを永遠に表示するコマンド [2] です。 こんなコマンドでも便利な場合があるのです。 表示がうっとうしいので、 出力は/dev/nullというデバイスファイル [3] に捨てています。 /dev/nullは、 単純に出力を捨てる働きを持つ特別なファイルです。

コマンドの次の行に表示されているのはなんでしょうか? はじめの数字がジョブ番号とよばれるものです。 次が、プロセスidです。 UNIXでは、すべてのプロセスに番号がつけられます。 プロセスはこの番号で管理されるのです。

しかし、永遠に終わらないプログラムを動かし続けると、 他の人に迷惑がかかってしまいます。 そこで、動いているプロセスを調べてこれを終わらせてやりましょう。 下の例を見て下さい。

	   >   ps
	  PID TT STAT  TIME COMMAND
	  14429 p6 S     0:02 -tcsh (tcsh)
	  24630 p6 R     7:17 yes
	  24772 p6 R     0:00 ps
	   >   kill -KILL 24630
	   >   ps
	  PID TT STAT  TIME COMMAND
	  14429 p6 S     0:02 -tcsh (tcsh)
	  24812 p6 R     0:00 ps
	  [1]  + Killed                 yes > /dev/null
	

コマンドpsを使うことで、現在動いているプロセスと そのプロセスid(PID)がわかります [4]

バックグラウンドプロセスを終了させるには、 killというコマンドで 殺してやる必要があります [5]。 確かに、killでプロセスを殺した後は psの出力にyesは なくなっていますね。 最後の行のメッセージは、シェルがプロセスが殺されたことを教えてくれているもので、 コマンドの出力ではありません。

でも、まだ2つプロセスが動いてるようですが、 これはほっておいていいのでしょうか? ひとつめは、シェルでこれを殺してしまうとlogoutしてしまいます。 ふたつめは、いま実行したps自身なので コマンドが終了すれば勝手になくなっています。 ということで、これ以上killできるものはなさそうですね。

パイプによるコマンドの連結:"|"

最後はパイプです。 普通、UNIXのコマンドは入力を標準入力から取り、 出力を標準出力に出すようになっています。 また、エラーメッセージは標準エラー出力に出されることになっています。

こういうふうにしておけば、いったいなにが嬉しいのでしょうか? その嬉しさが、パイプを利用することででてきます。

パイプは、その前にかかれたコマンドの標準出力とその後にかかれたコマンド の標準入力を結合します。 ちょうど、データが流れるための "パイプ"を用意してくれるのです。 つまり、あるコマンドの出力を次のコマンドに渡すことで、一つのコマンドで はできなかった複雑な動作が実現できることになります。 では、やってみましょう。

	     >   who
	    banbara  ttyp2    Jul 13 02:14 (nsg)
	    mutoh    ttyp6    Jul 12 09:58 (sentinel.info.na)
	     >   who | wc -l
	    2
	  
whoというコマンドは、 いま同じコンピュータにloginしている人を教えてくれます。 1行に一人かかれますので、 行数さえ分かれば何人がloginしているのかが分かりますね? そこで、wcを行数だけを出す -lオプションを利用して使ってやることで、 何人がloginしているのかを調べることができるようになりました。

パイプを用いた応用については「達人の技を盗め」を参照してください。

コマンド置換:"`command`"

コマンドの実行結果をコマンドラインで置き換える機能も用意されています。 これには、置換したいコマンドを"`"(backquote)で囲みます。 実際のコマンドの実行に先だってバッククオート内が評価され、 コマンドラインで展開された上で実行されます。

以下のようにすると、index.htmというファイルを、 index.htmlという名前に変更することができます。

	    > mv index.htm `basename index.htm .htm`.html
	  

Notes

[1]

ここでの実行単位がタスクです。 タスクがマルチ(複数)なのでマルチタスクですね。

[2]

引数を与えるとその文字列を表示します。

[3]

UNIXは全てがファイルであるといいましたが、 ハードディスクなどの周辺機器もファイルとして扱います。 この周辺機器をファイルのように利用するために用いられるのが、 デバイスファイルです。

[4]

psのコマンドラインオプションはちょっと変わっています。 マニュアルで確認してみて下さい。

[5]

killは実際には、シグナルと呼ばれる様々な信号を プロセスに対して送るためのものです。 でも、やっぱり"殺す"ことがおおいのでkillなんでしょうね。