以前rsyncでほぼTimeMachineと同様の増分バックアップを実現するシェルスクリプトを作成したのですが,プロバイダを変更したため該当ページが消えてしまったようなので,そのコードを下記に示します。参考になれば幸いです。
#!/bin/bash
#次の行にバックアップ先のボリューム名を直接指定するか,引数にバックアップ先ボリュームをドラッグアンドドロップして指定すること。
dest=/Volumes/backup01
#ディレクトリパスが引数として指定された場合,整形(最後のスラッシュを取る)してバックアップ先のボリューム名にする。
#それ以外の引数はディレクトリを整理する深さを決めるオプションスイッチとみなす。
if [ -d "$1" ]; then
dest=$(echo -n "$1" | sed 's/\/$//')
if [ "$2" ] ; then consoli=$2 ; fi
else
consoli=$1
if [ -d "$2" ]; then
dest=$(echo -n "$2" | sed 's/\/$//')
fi; fi
#このコマンド($0)をcron登録する際,コマンド名を絶対パスにする必要がある。
this=$(pwd)/$0
if [ -x $this ]; then
#コマンド名が相対パスだった場合,以下の手順で絶対パスに変換。(参考url=http://richlab.org/shellscript/ssr_support.html)
this=$(echo -n "$this" | sed 's/\/\{2,\}/\//g')
this=$(echo -n "$this" | sed 's/\/$//')
this0=""
while [ "$this" != "$this0" ]; do
this0="$this"
this=$(echo -n "$this" | sed 's/\/\.\//\//')
this=$(echo -n "$this" | sed 's/\/\.$//')
done
this0=""
while [ "$this" != "$this0" ]; do
this0="$this"
this=$(echo -n "$this" | sed 's/^\/\.\.\//\//')
if [ "$this" != "$this0" ]; then
continue
fi
this=$(echo -n "$this" | sed 's/^\/\.\.$/\//')
if [ "$this" != "$this0" ]; then
break
fi
this=$(echo -n "$this" | sed 's/\/[^\/]\{1,\}\/\.\.\//\//')
if [ "$this" != "$this0" ]; then
continue
fi
this=$(echo -n "$this" | sed 's/\/\([^\/]\{1,\}\)\/\.\.$//')
done
[ -z "$this" ] && this="/"
else
#コマンド名が絶対パスだった場合。
this=$0
fi
#このシェルスクリプトが置かれたディレクトリ(フォルダ)をバックアップ対象とする。
src=$(dirname $this)
user=$dest/$(basename $src)
now=$(date +%Y/%m/%d/%H)
base=$user/$now
log=$user/log/log.txt
start=$(date +%M:%S)
#バックアップ先ボリュームがマウントされているか確認する。
if ! df | grep "$dest\$" > /dev/null ; then echo "$dest not mounted."; exit 1 ; fi
#バックアップ先ボリュームがDOSフォーマットでないか確認する。
if diskutil list $dest | grep "DOS_FAT_32" ; then exit 2 ; fi
#バックアップ済みでないか確認する。この確認は不要かもしれない。
#if [ -d $base ] ; then exit 3 ; fi
#rsync ではバックアップ先の一つ上のフォルダまでは事前に作成しておく必要がある。
if [ ! -d $(dirname $base) ] ; then
mkdir -p $(dirname $base) && chmod -R 750 $(dirname $base) || exit 4
fi
#アクセス権不足でバックアップできないものがあった時のメッセージ。
warn="Some files and/or directories did not backuped."
cd $src
if [ -f $log ]; then
#2回目以降のバックアップなので前回バックアップ済みのものはそこからのハードリンクにする。
lastline=$(tail -n 1 $log)
preb=$user/$(printf "%.13s" "$lastline")
rsync -aE --exclude="*.sparseimage" --exclude="Library/Caches/Safari/" --link-dest=$preb ./ $base || echo $warn
if [ "$consoli" != "-l" -a "$consoli" != "-n" ] ; then
#日が変わったら,前日のバックアップは最後のものだけ残して削除する。TimeMachineは24時間分残すが,そこまで高級では無い。
yesterday=$(dirname $preb)
today=$(dirname $base)
if [ $yesterday != $today ] ; then
tmp=$user/yesterday
[ -d $tmp ] && rm -fR $tmp ||
mv $preb $tmp && rm -fR $yesterday && mv $tmp $yesterday
if [ "$consoli" != "-d" ] ; then
#月が変わったら,前月のバックアップは最後のものだけ残して削除する。TimeMachineは1週間単位だが,そこまで高級では無い。
lastmonth=$(dirname $yesterday)
thismonth=$(dirname $today)
if [ $lastmonth != $thismonth ] ; then
tmp=$user/lastmonth
[ -d $tmp ] && rm -fR $tmp ||
mv $yesterday $tmp && rm -fR $lastmonth && mv $tmp $lastmonth
if [ "$consoli" != "-m" ] ; then
#年が変わったら,前年のバックアップは最後のものだけ残して削除する。TimeMachineは残り容量で調節するが,そこまで高級では無い。
lastyear=$(dirname $lastmonth)
thisyear=$(dirname $thismonth)
if [ $lastyear != $thisyear ] ; then
tmp=$user/lastyear
[ -d $tmp ] && rm -fR $tmp ||
mv $lastmonth $tmp && rm -fR $lastyear && mv $tmp $lastyear
fi; fi; fi; fi; fi; fi
else
#ログファイルが無いので,最初のバックアップ。
#ダブルクリックでこのコマンドを実行できるファイルを作成する。
xname=$user/inc_backup.command
echo "#!/bin/sh" > $xname
echo "x=$this; [ -x \$x ] && \$x $dest -l" >> $xname
mkdir -p $(dirname $log) && chmod -R 750 $user
if [ "$USER" = "$(basename $user)" ] ; then
chown -R $USER $user
if [ ! "$USER" = "root" ] ; then
#このコマンドを起動したユーザのデスクトップにこのコマンドを実行するショートカットアイコンを作成する。
[ -d $HOME/Desktop -a -e $xname ] && ln -s $xname $HOME/Desktop/$(basename $user)_backup
fi
else
[ "$SUDO_USER" = "$(basename $user)" ] && chown -R $SUDO_UID:$SUDO_GID $user
fi
rsync -aE --exclude="*.sparseimage" --exclude="Library/Caches/Safari/" ./ $base || echo $warn
fi
#ログファイルに開始日時と終了時刻とディスク使用量を追記で記録する。
echo "$now:$start;$(date +%T),$(df | grep "$dest\$")" >> $log
#root権限で起動されている場合,終了時刻の1時間後から毎時刻(分が同じときに)このコマンドをroot権限で実行するように登録する。
if [ "$USER" = "root" ] ; then
crontab=$(crontab -lu root 2> /dev/null)
#このコマンドが既に登録されていないか確認する。
if ! echo "$crontab" | grep "$this" > /dev/null; then
crontab=$(echo "$crontab"; echo "$(date +%M) * * * * x=$this; [ -x \$x ] && \$x $dest $consoli")
#未登録の場合,既存のcrontabにこのコマンドを追加したものに登録し直す。
echo "$crontab" | crontab -u root
fi; fi