Skip to content

Instantly share code, notes, and snippets.

@kkotaro0111
Last active August 19, 2025 05:24
Show Gist options
  • Save kkotaro0111/3c85f0467ba389f07b1dbb45e90eedce to your computer and use it in GitHub Desktop.
Save kkotaro0111/3c85f0467ba389f07b1dbb45e90eedce to your computer and use it in GitHub Desktop.
mozjpegで指定したフォルダ内の画像を再圧縮する
#!/usr/bin/env bash
# エラーが発生した場合、およびパイプラインでエラーが発生した場合にスクリプトを終了する
set -e
set -o pipefail
# --- ヘルプメッセージ ---
usage() {
cat <<EOF
Usage: $(basename "$0") [OPTIONS] <directory> <quality>
Re-compresses all JPEG files in a directory using mozjpeg's cjpeg.
Original files are moved to a subdirectory named '_original'.
Arguments:
<directory> The target directory containing JPEG files.
<quality> The compression quality (0-100).
Options:
-n, --dry-run Show what would be done, without actually modifying any files.
-h, --help Display this help message and exit.
EOF
exit 1
}
# --- 初期値 ---
DRY_RUN=0
# --- オプション解析 ---
# getoptsではなく、より柔軟なループを使用
while [[ $# -gt 0 ]]; do
case "$1" in
-n|--dry-run)
DRY_RUN=1
shift # 引数をシフト
;;
-h|--help)
usage
;;
--)
shift # -- の後を引数として扱う
break
;;
-*)
echo "Unknown option: $1"
usage
;;
*)
break # オプション以外の引数が見つかったらループを抜ける
;;
esac
done
# --- 引数のチェック ---
if [ "$#" -ne 2 ]; then
echo "Error: Missing directory or quality argument."
usage
fi
TARGET_DIR=$1
QUALITY=$2
COMPRESSED_DIR="$(dirname "$TARGET_DIR")/$(basename "$TARGET_DIR")_compressed"
# --- 依存関係のチェック ---
for cmd in cjpeg find mv mkdir basename; do
if ! command -v "$cmd" &> /dev/null; then
echo "Error: Required command '$cmd' is not available in your PATH."
exit 1
fi
done
# --- 入力値の検証 ---
if [ ! -d "$TARGET_DIR" ]; then
echo "Error: Directory '$TARGET_DIR' not found."
exit 1
fi
if ! [[ "$QUALITY" =~ ^[0-9]+$ ]] || [ "$QUALITY" -lt 0 ] || [ "$QUALITY" -gt 100 ]; then
echo "Error: Quality must be a number between 0 and 100."
exit 1
fi
# --- ドライランの表示 ---
if [ "$DRY_RUN" -eq 1 ]; then
echo "*** This is a DRY RUN. No files will be changed. ***"
echo "----------------------------------------------------"
fi
echo "Target directory: $TARGET_DIR"
echo "Quality: $QUALITY"
echo "Comporession directory: $COMPRESSED_DIR"
echo ""
# --- 処理の実行 ---
if [ "$DRY_RUN" -eq 0 ]; then
mkdir -p "$COMPRESSED_DIR"
fi
processed_files=0
# findで見つかったファイルを配列に格納してからループ処理
mapfile -t -d '' files < <(find "$TARGET_DIR" -type f \( -iname "*.jpg" -o -iname "*.jpeg" \) -print0)
for file in "${files[@]}"; do
filename=$(basename "$file")
# 相対パスを取得してサブディレクトリ構造を保持
relative_path="${file#$TARGET_DIR/}"
convert_file="${COMPRESSED_DIR}/${relative_path}"
working_dir=$(dirname "$convert_file")
if [ "$DRY_RUN" -eq 1 ]; then
echo "[DRY RUN] Would re-compress to '$convert_file' with quality $QUALITY"
else
echo "Processing: $relative_path"
# 1. 作業ディレクトリを作成
if ! mkdir -p "$working_dir"; then
echo "Error: Failed to create working directory '$working_dir'"
continue
fi
# 2. 再圧縮
if cjpeg -quality "$QUALITY" "$file" > "$convert_file" 2>/dev/null; then
echo "✓ Successfully processed: $relative_path"
else
echo "Error: Failed to compress '$relative_path'."
continue
fi
fi
processed_files=$((processed_files + 1))
done
echo "----------------------------------------------------"
if [ "$processed_files" -eq 0 ]; then
echo "No JPEG files found to process."
else
if [ "$DRY_RUN" -eq 1 ]; then
echo "Dry run complete. Found $processed_files JPEG file(s)."
else
echo "Successfully re-compressed $processed_files JPEG file(s)."
fi
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment