第1章 初めてLinux/UNIX系OSにふれる
エンジニアのための最初の一歩(5)

シェルとコマンド(3)

 

1.2シェルとコマンド(その3) 

ループ

 シェルで繰り返しを行うときはfor文がよく使われます.bashにはfor以外にもループを構成する構文がありますが,Bourne shellにはfor文しかありません.for文は,

  for name in word; do リスト ; done

という構成をしています.wordに指定された空白で区切られた単語を順にname変数へ入れてリストを実行します.in word;の部分は省略可能で,省略すると位置パラメータがかわりに使われます.

 次に示す例では,ルートディレクトリにある各ディレクトリがそれぞれいくつのファイルを持っているかを表示します.

$ for i in /*; do echo $i;ls $i|wc; done

 *はその位置に任意の文字列を入れてできるファイル名にマッチします.“/*”はルートディレクトリにある‘.’で始まらないすべてのファイル名に置き換えられます.これは,

  $ echo /*

で確認できます.展開されたファイル名は順番に変数iに代入され,doとdoneの間のリストを実行します.シェルの変数は$iのように‘$’をつけて参照します.

 ‘*’はシェルにとって特別の意味をもつ記号で,メタキャラクタと呼ばれます.‘*’はシェルによって展開される代表的なメタキャラクタの一つです.echoコマンドは,引き数を標準出力へ出力するだけです.先ほどのechoの例では,echoの引き数はシェルによりすでに,

  echo /bin /boot /dev ...

のように展開されています.シェルには,‘*’以外に任意の1文字にマッチする‘?’と,指定された中の1文字にマッチする[ccc]があります.

条件分岐

 シェルの条件分岐にはcase文とif文がありますが,ここではif文を取り上げます.if文は,次のように使います.

  if リスト then リスト else リスト fi

 リストは必ず;,&または改行で終わることに注意してください.if文は,最初のリストを実行してそのコマンドが成功すれば(コマンドの終了ステータスが0の場合),thenの後のリストが実行され,それ以外の場合にはelseの後のリストが実行されます.

 if文は,システムの初期化スクリプトでもよく使われています.これらのファイルでは,if文の条件にtestコマンドがよく使われます.testコマンドはファイルの種類のチェックや値の比較を行います.bashではtestコマンドは組み込みコマンドになっていて,test ...は[ ... ]と書くこともできます.先の例を/以下のファイルがディレクトリの場合だけ,そのディレクトリのファイルの数を数えるようにするにはif文が必要です.

  $ for i in /*

  > do

  > if [ -d $i ]; then

  > echo $i;ls $i|wc 

  > fi

  > done

 上記の‘>’は2次プロンプトと呼ばれるもので,コマンドがまだ完結していないときにシェルが表示します.[ -d $i ]は test -d $i と書いても同じです.-dオプションは,引き数のファイルがディレクトリであるかどうかを調べ,ディレクトリであればtestコマンドは成功します(0を返す).

 なお,複合コマンドもコマンドであることに違いはないので標準入出力をリダイレクトすることができます.最後のdoneの後に“>num”を追加すれば,numというファイルに結果が出力されます.また‘|’記号を使って,パイプラインを構成することもできます.

cshから受け継がれている機能(その1)

 cshは,カリフォルニア大学バークレー校で開発されたシェルです.bashは,対話的に使われるときの機能の多くをcshから引き継いでいます.

ジョブ制御

 すでに説明したように,コマンドに&をつけて実行するとバックグラウンドプロセスとして実行されます.

  $ sleep 30&

  [1] 2884

 このとき,シェルは[]で囲まれたジョブ番号とプロセスID(パイプラインの場合は最後のプロセスのプロセスID)を表示します.カーネルは,各プロセスに一意なIDをつけて管理します.ここで,psコマンドを使うことで,現在のプロセスの一覧を表示することができます.

 一方,bashはパイプラインを一つのジョブとしてジョブ番号で管理します.jobsコマンドで,現在のジョブの一覧を表示できます.いま,たとえば,

  $ man sleep

でsleepコマンドのマニュアルページを見ているとします.manコマンドは端末からの入力を待っていて,スペースを打つと次のページを表示し,Bを入力すると1ページ前に戻ります.ここで^Zを入力します(正確にはサスペンド文字で,sttyコマンドで変更できる).

 するとmanコマンドは一旦停止し,bashのプロンプトへ戻ります.これは,プロセス間通信のもっとも基本的なシグナルという機能を使って実現されています.ここで,^Zを入力すると端末ドライバはTSTPシグナルを現在のジョブに送り,TSTPシグナルを受け取ったプロセスは停止します.

 manコマンドが停止しているときに,

  $ ps lww

でプロセスの状態(STAT)を見ると,manコマンドによるパイプラインがT(停止)になっていることがわかります.このような状態でmanコマンドを再開するには,

  $ fg

とします.

 これとは逆に,findやmakeのように時間のかかる処理を&をつけずに実行すると,次のコマンドが実行できません.この場合は^Zを入力して,プロセスを停止し,

  $ bg

とすれば,バックグラウンドで実行を継続させることができます.

 端末ドライバでは,TSTPシグナル以外にINTシグナルとQUITシグナルをプロセスに送ることができます.

 INTシグナルはプロセスを中断させます.通常は,^Cを入力することでコマンドを中断することができます.

  $ sleep 1000

  ^C

 なお,任意のシグナルを送るためにはkillコマンドを使います.

 図11に,以上のことをまとめた,ジョブ制御の概略を示します.

(図11)

ジョブ制御

(約9Kバイト)


Copyright 2000 
日樫 英孝/増田 佳泰/山岡 賢一/船木 陸議/ 羅 正華/森 友一朗/祐安 重夫/岩田 孝清/海老原 祐太郎/g新部 裕/ 齊藤 正伸

新刊のご案内


Copyright 1997-2001 CQ Publishing Co.,Ltd.