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

[9/28, 2009 H.Aman]
67x27(1669bytes)   67x27(1669bytes) 【課題 1】

例題 1

カレントディレクトリに置かれている全ての C ソースファイル(拡張子 .c) について,そのコピーを生成するシェルスクリプト makecopy.sh を作りなさい. ただし,コピーによって新たに作られるファイルの名称は, 元のファイル名の頭に "copy_" を付けたものとする.

※次のサンプルファイル pr2-2-ex1.tar.gz を右クリックし,「名前を付けてリンク先を保存」を選んでダウンロードすること.
そして,

     $ tar zxvf pr2-2-ex1.tar.gz
というコマンドを実行すると,カレントディレクトリに pr2-2-ex1 という名前のディレクトリが自動的に作られ,その下に 3 つの C ソースファイルが作られる:
     $ cd pr2-2-ex1
     $ ls
     bar.c  foo.c  hoge.c
ここで,「自作の makecopy.sh を実行すれば, それぞれのコピーが作られる」 というのが本例題の目的である:
     $ bash makecopy.sh
     $ ls
     bar.c  copy_bar.c  copy_foo.c  copy_hoge.c  foo.c  hoge.c

解答例

     for name in *.c
     do
       cp $name copy_$name
     done
     

解説

ここでは,単に cp コマンドを使ってファイルのコピーを作るだけであるが, その操作を繰り返し行うという点に注目する.

基本的には,foo.c というファイルがあれば,これに対して

     $ cp foo.c copy_foo.c
という具合いに cp コマンドを実行すればよい.
ただし,ここで問題となるのは, 処理対象のファイルがどのような名前でいくつあるのかは与えられていない. もしも,100 個の異なる名前の C ソースファイルがあったとすれば, 上述の cp コマンドを 100 回書かなければならないため, とてもではないが現実的ではない.

そこで for 文を使った繰り返し でこれを実現する.

for 文は次のかたちで構成される:


     for  変数名  in  リスト
     do
        繰り返して実行したいコマンド(複数行も可)
     done

まずは簡単な例を見てもらいたい. 次の内容を実行すると,
     for  x  in 1 2 3 a b c
     do
        echo $x
     done
その結果は
     1
     2
     3
     a
     b
     c
となる.
ここでは, 変数 x へ 1, 2, 3, a, b, c という文字列が順番に代入 されながら, その都度,do と done の間のコマンドが実行 されている.
do と done の間には echo $x と書いてあるため,変数 x の内容が一行で表示される.

ここで,変数(正確にはシェル変数)の取り扱いについて少し補足しておく:

  • 変数の宣言は特に必要ない
  • 変数の内容を参照する場合は,変数名の頭に $ マークを付ける
    代入する時には $ マークは付けない

また,変数の代入元となる「リスト」であるが, 上の例のように一つずつ列挙してもよいし, *.c といったワイルドカード表現を使ってもよい.
*.c とした場合,「ls *.c」を実行するのと事実上は同じであり, ファイル名が .c で終わるものだけが自動的に列挙される.

以上の点をふまえて例題の解答例を見ていく.
(1)まず,ファイル名が .c で終わるファイルのリストを用意し, 一つずつ順番に name という変数に代入していく

     for name in *.c

(2)変数 name へ代入が行われるたびに do と done の間のコマンドが実行される.

(3)変数 name で表されるファイルをコピーする. コピー先の名称は頭に copy_ を付けたものである:

     cp $name copy_$name