OptiPNGとJpegoptimを実行するスクリプトの紹介

先日の記事で紹介したOptiPNGJpegoptimを、特定のディレクトリ以下に対して実行するスクリプトを紹介します。例えば、「WordPressで画像をアップロードし、記事を公開する前に画像を圧縮しておく」といった具合に使えるようにしてあります。

また、古いファイルは作業対象に含めず、なるべくサーバ負荷を抑えつつ作業できるように工夫しています。

使用するコマンドの説明

今回のスクリプトでは、findコマンドとrsyncコマンドを使用します。そこで、その2つのコマンドについて簡単に紹介しておきます。

findコマンド

findコマンドの使い方は、以前書いた記事指定したディレクトリの中にある、ファイルの合計サイズを取得する方法で紹介していますので、基本的な使い方はそちらをご確認頂ければと思います。

加えて、この記事では更新後xx分以内のファイルのみを検索対象とするという絞り込みをかけています。その使い方についても説明しておきます。

更新時間で検索対象を絞り込む

findコマンドに-mtime -xxと指定すると、更新からxx日以内(xx * 24時間)のファイルを検索対象とすることができます。例えば、1日以内に更新したファイルを検索対象にする場合は、-mtime -1と指定します。

# findに引っかかるファイルを用意します。
$ echo FIND_TEST > /tmp/find_mtime_test

# 更新日が1日以内のファイルを検索します。
$ find /tmp -type f -mtime -1

上記findコマンドで、たった今作成されたfind_mtime_testが対象になることを確認できるかと思います。

他にも-mtime xx-mtime +xxで更新日が古いファイルを対象にしたり、-mmin -xxでxx以内に更新されたファイルを対象にしたりできます。この辺の使い方は、man findで調べることができます。

rsyncコマンド

rsyncはファイルやディレクトリの同期を取るコマンドです。向き先を別のサーバにすることでバックアップに使ったり、複数台の配信用サーバにファイルを配置したり、様々な用途で使うことができます。

例えば、rsyncコマンドを打つサーバの/tmpディレクトリと、remotestance.comというサーバの/tmpディレクトリを同期したい場合は以下のようになります。

$ rsync -av /tmp/ remotestance.com:/tmp/

便利なオプションの紹介

--dry-runオプション

ファイルの転送を実施せずに実行結果が表示されます。rsyncコマンドを使うときは、まずは--dry-runを付けて実行結果を確認し、次に--dry-runを外すことで事故の確率を下げることができます。

--deleteオプション

同期元で削除されたファイル・ディレクトリがあった場合に、同期先からも削除されるようになります。

--checksumオプション

ファイルの比較を日付やサイズではなく、チェックサムで比較するようになります。これを使うと、日付が更新されているけれども中身が変わっていないファイルを同期対象から外すことができます。

処理の流れ

公開中の画像を圧縮するケースを考慮して、対象のファイルを直接は圧縮しません。先にrsyncで作業用のディレクトリに同期させておき、作業用のディレクトリで圧縮します。そして、作業用のディレクトリから対象のファイルを同期させます。

  1. 圧縮対象のディレクトリから作業ディレクトリに同期します。
  2. 作業ディレクトリのPNG画像を圧縮します。
  3. 作業ディレクトリのJPEG画像を圧縮します。
  4. 作業ディレクトリから圧縮対象のディレクトリに同期します。

画像圧縮するスクリプト

それでは、画像を圧縮するスクリプトを紹介します。

#!/bin/sh
OPTIPNG_BIN=/usr/local/bin/optipng
JPEGOPTIM_BIN=/usr/local/bin/jpegoptim

# 作業用のディレクトリを定義します。
# ※最後は/で終わるようにします。
WORK_DIR=/tmp/works/image_compression/

# 圧縮対象の画像が含まれるディレクトリを定義します。
# ※最後は/で終わるようにします。
#   例) TARGET_DIR=/var/www/remotestance.com/__wp__/wp-content/uploads/
TARGET_DIR=<TARGET_DIR>

# 何日以内に更新された画像を対象とするかを定義します。
MDATE=1

# 作業用ディレクトリを作成します。
mkdir -p $WORK_DIR

# 圧縮対象のディレクトリを、作業用ディレクトリに同期させます。
rsync -avz --checksum $TARGET_DIR $WORK_DIR

# 作業用のディレクトリのPNGファイルを圧縮します。
find $WORK_DIR -name "*.png" -type f -mtime -$MDATE -exec $OPTIPNG_BIN -o7 {} ;

# 作業用ディレクトリのJPEGファイルを圧縮します。
find $WORK_DIR -name "*.jpg" -type f -mtime -$MDATE -exec $JPEGOPTIM_BIN --strip-all {} ;

# 作業用ディレクトリを、圧縮対象のディレクトリに同期させます。
rsync -avz --checksum $WORK_DIR $TARGET_DIR

権限に関する注意点

このスクリプトは、圧縮対象のファイルの所有者と同じ権限で実行する必要があります。例えば、圧縮対象画像の所有者がNginxである場合は、以下のように実行します。

$ sudo -u nginx sh スクリプト

実行ユーザを変える理由

2回目のrsync、つまり作業用ディレクトリから元のディレクトリに同期するときに、ファイルの書き込み権限が必要だからです。

root権限で実行してはいけない理由

わたしが使ったOptipng version 0.7.5では、root権限で実行すると圧縮されたファイルの権限がrootになっていました。それにより、元のディレクトリに同期した後、PNG画像の権限がrootになってしまいました。そうすると、ファイルのパーミッションが644だとして、WordPressなどから画像の更新や削除ができないということが発生することが予想されます。

余談ですが、rsyncの-aに-oと-gが含まれていて、これらオプションは所有者とグループを維持したまま同期できます。そのため、root権限で実行しようが作業用ディレクトリの権限さえ変更されていなければ問題なかったのですが、作業用ディレクトリの方の権限が変わってしまうのでダメでした。。。

ソースコード

今回のスクリプトをgithub上に公開しました。https://github.com/yusukemurayama/blog-samples/blob/master/201506/compress_image/compress_image.sh

この記事が役に立った場合、シェアしていただけると励みになります!!