シェルスクリプト作成のテクニック Part 1

Hiroshi Tomioka
(2008年9月 9日 12:00) |

※このエントリーは、developerWorks : AIX and UNIXの「Speaking UNIX: More shell scripting techniques」を翻訳したエントリーのPart 1です。

他のUNIXやLinuxと同じように、IBM AIXにはシステム管理者や開発者、そしてユーザーが日時タスクや業務の効率化に取り組む際に味方となる強力なツールが存在します。その一つがシェルスクリプトです。

とはいえ、UNIXと数年付き合い、シェルスクリプトに手を出してきた人でも、オペレーティングシステムの裏側については勉強中で、まだまだスクリプトをマスターとしたとは言えない人も多いと思います。この記事では、シェルスクリプトとは何かから始まり、より高度なスクリプトを書く方法をご紹介します。一般的なプログラミングの基礎から簡潔なスクリプトの書き方、より柔軟性のあるスクリプトの書き方、明快なスクリプトの書き方、スクリプト内のドキュメンテーション方法、そしてスクリプトのデバッグがその内容です。

スクリプトは簡潔に

シェルスクリプト学習の世界に入ってきた人々が直面する問題の一つが、すでにスクリプト内に記述した処理をもう一度記述しようとしてしまうことです。それらの処理をコピーして、ハードコードされた値を変更するのではなく、関数を作って両方の処理を扱えるようにすることで、スクリプトを簡潔にすることが出来ます。関数を一箇所に集めれば、スクリプトが標準化され、一定の形式を保つことが出来ます。スクリプトのある箇所から呼び出された関数が正常に動くならば、他の箇所から呼び出されても正しく動く可能性がある程度保障されます。

それでは例題です。Listing 1のスクリプトを凝縮させ、短くより明快なプログラムへと簡潔化させて下さい。

Listing 1: より簡潔に記述できるスクリプトの例

#!/usr/bin/ksh

if [[ $# -lt 2 ]]
then
  echo "Usage: ${0##*/}  "
  exit 0
fi

if [[ ! -f "${1}" ]]
then
  echo "Unable to find file '${1}'"
  exit 1
fi

if [[ ! -r "${1}" ]]
then
  echo "Unable to read file '${1}'"
  exit 2
fi

gzip ${1}
ls -l ${1}.gz


if [[ ! -f "${2}" ]]
then
  echo "Unable to find file '${2}'"
  exit 1
fi

if [[ ! -r "${2}" ]]
then
  echo "Unable to read file '${2}'"
  exit 2
fi

gzip ${2}
ls -l ${2}.gz

このスクリプトは本当にひどいと思います(有難いことにこれはただの例題です)。スクリプトは出来るだけ凝縮させましょう。読者の目の疲労も考えて、Listing 2ではより明快なバージョンのスクリプトを掲載します。

Listing 2: Listing 1のスクリプトを凝縮させたもの

#!/usr/bin/ksh

exit_msg() {
  [[ $# -gt 1 ]] && echo "${0##*/} (${1}) - ${2}"
  exit ${1:-0}
}

[[ $# -lt 2 ]] && exit_msg 0 "Usage: ${0##*/}  "

for _FNAME in $@
do
  [[ ! -f "${_FNAME}" ]] && exit_msg 1 "Unable to find file '${_FNAME}'"
  [[ ! -r "${_FNAME}" ]] && exit_msg 2 "Unable to read file '${_FNAME}'"

  gzip ${_FNAME}
  ls -l ${_FNAME}.gz
done

違いに気付かれましたか?メッセージの表示とリターンコードを返すための簡単な関数を追加しました。また、すべての引数をforループで処理させることにより、より簡潔で理解しやすくしました。

【訳注】 「シェルスクリプト作成のテクニック Part 2」に続きます。