HOME 備忘録 書き込む

関数プログラミング的なシェルスクリプト


Mar 18, 2007

ご存知のように、POSIX (UNIX, Linux など) では bash などのシェルスクリプトをもちいて 処理を自動化できます。ここでは、シェルスクリプトを関数言語的に味付けして遊んでみました。

bash の関数は再帰的に呼び出すことが可能なので、例えば、階層的なディレクトリ構造以下の 全てのファイルに同じ処理を施したいときは以下のような簡単なスクリプト (for_all) でできます。
このスクリプトで 変数 FULLlocal で宣言しているのがミソで、 こうすることによって、変数が関数内だけで有効になるので、関数を再帰的に定義することができるようになります。
for_all の内部で定義されている関数 rec は以下のように動作します。

[for_all]

#! /bin/bash

function rec {
    for FILE in `ls ${2}`
        do
           local FULL=${2}/${FILE}
           if [ -f $FULL ]; then $1 $FULL
           elif [ -d $FULL ]; then rec $1 $FULL
           fi
        done
}

rec $1 `pwd`/${2}
実用的な例として、for_all を使ってあるディレクトリ以下の改行コードを全て \r\n (MicroSoft 形式) から \n (UNIX 形式) に換えてみます。 次のような簡単なスクリプト (ms2uinx) を for_all の第一引数として渡せば 実現できます。tr は便利な 文字の変換、圧縮、削除 ツールで、使い方は http://www-06.ibm.com/jp/developerworks/linux/030523/j_l-tiptex5.html などをご覧ください。

[ms2unix]

#! /bin/bash

cat $1 | tr -d '\r'  > $1

例えば、カレントディレクトリの下に win_texts という階層的な構造を持つディレクトリがあり、 その中の全てのファイルの改行コードを \r\n から \n に換えたいときは、

$ for_all ms2unix win_texts
とすればできます。 for_all の第一引数は手続きなので、手続きを変えることによりいろいろなことができます。 例えば、ディレクトリ dir1 以下のファイル名と内容を全部表示させたいときは、 次のようなスクリプトを for_all の第一変数に渡して これを実行します。

[name_cat]

#! /bin/bash

echo "[ $1 ]"
cat $1
echo "[EOF]"
echo""
$ for_all name_cat dir1

また、for_all をちょっと改良すると特定の拡張子のファイルだけを処理するようにもできます。 試してみてください。

for_all は以下の2つの理由で関数プログラミング風です。

  1. 内部で再帰関数 (rec) を使っている。
  2. 引数に手続きをとる高階関数。
bash を関数プログラム風に使うのも楽しいですね。
なお今回のねたは、読者の方の書き込みから着想を得ました。