シェルスクリプトによる特定ファイルのバックアップUNIX処方箋

「事件は枯れたシステムが稼働する現場で起こってるんだ」と現場ですぐに役立つ知識を欲するあなたに贈る珠玉のTips集。今回は、シェルスクリプトを使って、特定のファイルが更新された場合のみバックアップする方法を解説する。

» 2008年04月01日 00時00分 公開
[ITmedia]

Solaris上でシェルスクリプトを使って、特定のファイルが更新された場合のみバックアップするようにしたいのですが、どうしたらよいでしょうか? スクリプトに使っているシェルは/bin/shです。


例えば、ユーザーアカウントやパスワードの変更があった場合に、/etc/passwd、/etc/shadowファイルのバックアップを取るなど、不定期に更新されるファイルの場合、更新されたもののみバックアップしたいという要求があります。これなら、シェルスクリプトを組んで、cronで定期的に実行させることで比較的手軽に実現できそうです。

 以下の方針でスクリプトを組み立てることにしましょう。

  1. /etc/passwd、/etc/shadowを適当な周期で監視し、ファイルが更新されていたらバックアップを取る
  2. それぞれのファイルのバックアップファイルと現在のファイルを比較し、更新されていたらバックアップファイルを新たに作成する
  3. バックアップファイルを、バックアップ日時ごとにファイル名を分けて保存する

 この中で問題になりそうなのが、「ファイルが更新されたことをどうやって検知するか」という点です。幾つか考えられる方法を挙げてみましょう。

  • 「ls -l」コマンドで表示されるタイムスタンプを比較

 この方法は単純ですが、文字列の抽出や比較を行うことが必要で、シェルスクリプトには荷が重いでしょう。

  • diffコマンドで、現在のファイルとバックアップファイルに差異がないかどうか確認

 lsを用いる方法に比べればはるかに現実的です。しかし、diffで確認できるのはファイル内容の差分だけであり、どちらが「更新」された内容なのかは判断がつきません。

testコマンド

 lsやdiffによる方法はいずれも一長一短で、もっと簡単な方法が望ましいところです。testコマンドに、ちょうど利用できそうな「-nt」および「-ot」オプションがあります(表1)。さっそくこれらを利用して、リスト1のように試験的にスクリプトを組んでみましょう。

オプション 説明
file1 -nt file2 ファイルfile1が存在し、(修正時刻で比較して)ファイルfile2よりも新しい場合は真
file1 -ot file2 ファイルfile1が存在し、ファイルfile2よりも以前のものである場合は真
表1 testコマンドのファイル特性関連オプション(抜粋)

#!/bin/sh
DATE=`/bin/date '+%Y%m%d%H%M'`
if [ /etc/passwd -nt /var/bak/passwd ] ←コピー元(/etc/passwd)とバックアップ先(/var/bak/passwd)を比較
then
    cp -p /etc/passwd /var/bak/passwd ←コピー元がバックアップ先より新しければバックアップ先への上書き
    cp -p /etc/passwd /var/bak/passwd.$DATE ←タイムスタンプ付きファイル名へのコピー
    echo "detected /etc/passwd is updated." ←メッセージを出力
fi

リスト1 testコマンドの「-nt」および「-ot」オプションを利用したサンプルスクリプト

 リスト1では、コピー元(/etc/passwd)とバックアップ先(/var/bak/passwd)を比較し、コピー元がバックアップ先より新しければバックアップ先に上書きし、さらにタイムスタンプ付きファイル名へのコピーも同時に行っています。「cp -p」を利用する理由は、バックアップ先ファイルにコピー元ファイルのタイムスタンプ情報を保持させ、タイムスタンプの比較が正しく行われるようにするためです。また実行結果を分かりやすくするため、メッセージも出力させることにします。

 しかし、Solaris上でリスト1を実行すると、以下のような結果となってしまいます。実は、Solarisの/bin/sh組み込みのtestコマンドでは、「-nt」、「-gt」演算子はサポートしていません。この解決方法は2つ考えられます。

# chmod 755 backup.sh

# ./backup.sh

./backup.sh: test: unknown operator -nt


/bin/testコマンドを使用

sh組み込みコマンドではなく、外部コマンドの/bin/testを利用します。この場合、リスト1のif文を次のように書き換えます。

if /bin/test "$ORIGINAL" -nt "$BACKUP"


 しかし、外部コマンドは子プロセスとして起動されるため、あまり頻繁に呼び出すとパフォーマンスの低下につながる恐れがあります。

/bin/sh以外の互換シェルを利用

 Solarisを含むSVR4系*に標準装備されている/bin/kshや、Solaris 10でも標準搭載されるようになったbashなどの拡張されたシェルを利用します。利用が増えているLinux系などとの互換性を考慮すると、bashを利用するとよいでしょう。

 /bin/testコマンドを利用して、保存先の管理など実用になるように修正を加えたものがリスト2です。


#!/bin/sh
ORIGDIR=/etc
BACKDIR=/var/bak
DATE=`/bin/date '+%Y%m%d%H%M'`

for i in passwd shadow do         if /bin/test $ORIGDIR/$i -nt $BACKDIR/$i         then                 cp -p $ORIGDIR/$i $BACKDIR/$i                 cp -p $ORIGDIR/$i $BACKDIR/$i.$DATE                 echo "detected $ORIGDIR/$i is updated."         fi done
リスト2 /bin/testを利用するようにリスト1を修正

 後は、10分、1時間、1日など適当な周期ごとにcronでリスト2を起動すれば、その時点で変更が検知されたファイルだけをバックアップできます。

 シェルスクリプトを利用する際、testコマンドは非常に便利かつ重要なものですが、シェルの種類による差異や、組み込みコマンドと外部コマンドの違いなど、分かりにくい部分もありますので注意が必要です。

このページで出てきた専門用語

SVR4系

1987年、AT&TとSun Microsystemsが提携し、その後BSD系OSの機能を追加した統合UNIXがUNIX System V Release 4(SVR4)として開発された。Solarisはこの流れをくむ。


関連キーワード

バックアップ | Solaris | UNIX | UNIX処方箋


Copyright © ITmedia, Inc. All Rights Reserved.

注目のテーマ