第 2 回 - フィルタ,シェルスクリプトの基礎(2)

[10/10, 2009 H.Aman]
67x27(1669bytes)   67x27(1669bytes) 【課題 2】

例題 2

自分のホームディレクトリ以下(サブディレクトリも含む)に存在する全ての C ソースファイル(拡張子 .c)に対し,その名前の一覧を表示するシェルスクリプト clist.sh を作りなさい. ただし,各ソースファイル名の拡張子(末尾の .c)は取り除いて出力すること.

解答例

     list=$(find ~ -name "*.c")
     for name in $list
     do
       echo ${name%.c}
     done
     

解説

まず,find コマンドを使って自分のホームディレクトリ以下に存在する全ての C ソースファイル(拡張子 .c)をリストアップしている.

試しに

     find ~ -name "*.c"
を実行してみるとよい.
これは自分のホームディレクトリ~)以下で名前が *.c に合致 するものだけを表示するという動きをする.

ここでポイントなのは, その実行結果をシェル変数 list に代入している ことである.
シェルスクリプトの中では, $() でコマンドを囲んでやると,下請けのかたちで先に実行してくれ, その結果を変数に代入できるのである:

     list=$(find ~ -name "*.c")
     for name in $list
     do
       echo ${name%.c}
     done

次に,その find の実行結果(変数 list)を for 文のリストに利用している.
ここでは変数 name へ次々と list の内容が順番に代入され, その都度,do と done の間が実行される.

ここでもう一つのポイントは

     list=$(find ~ -name "*.c")
     for name in $list
     do
       echo ${name%.c}
     done
という具合いに,変数 name に少し修飾が施されている点である.

${name%.c} という具合いに % マークを付けて書くと, 変数 name の内容のうち, 指定された文字列を末尾から削除 されたものが使われるという働きがある.
この場合,% の横に .c と書いてあるため, name の内容の末尾から .c を削除 したものが使われる.
したがって,echo コマンドを使って表示されるのは, 末尾の .c を取り除いたファイル名ということになる.

(参考)
同様に,次の使い方が許されている:
使い方 意 味
  ${variable#pattern}  variable の値の最初の部分と pattern が一致した場合, もっとも短く一致する部分を削除して残りの部分を返す
 ${variable##pattern}  variable の値の最初の部分と pattern が一致した場合, もっとも長く一致する部分を削除して残りの部分を返す
 ${variable%pattern}  variable の値の終りの部分と pattern が一致した場合, もっとも短く一致する部分を削除して残りの部分を返す
 ${variable%%pattern}  variable の値の終りの部分と pattern が一致した場合, もっとも長く一致する部分を削除して残りの部分を返す

(例)次のスクリプトを考える:

     aaa=/usr/local/bin/mule
     echo "(1) $aaa"
     echo "(2) ${aaa#/*/}"
     echo "(3) ${aaa##/*/}"
     echo "(4) ${aaa%/*/}"
     echo "(5) ${aaa%%/*/}"
これを実行すると
     (1) /usr/local/bin/mule
     (2) local/bin/mule
     (3) mule
     (4) /usr/local/bin/mule
     (5) /usr/local/bin/mule
となる. (2) ,(3) は先頭から /*/ というパターンにマッチする. そこで,(2) は最も短い /usr/ に, (3) は最も長い /usr/local/bin/ にそれぞれマッチするためそれらが削除されて上の結果になる. また,(4),(5) は同じパターンマッチを後ろから試みているが, この aaa の値は / で終っていないのでマッチしない.