Skip to content

Instantly share code, notes, and snippets.

@ponkotuy
Created June 18, 2026 16:55
Show Gist options
  • Select an option

  • Save ponkotuy/0ba8c127b5f4b5a4ab53e580032b97da to your computer and use it in GitHub Desktop.

Select an option

Save ponkotuy/0ba8c127b5f4b5a4ab53e580032b97da to your computer and use it in GitHub Desktop.
写真ディレクトリにある撮って出しJPEGを消し飛ばしてrawの中身を抽出して展開するスクリプト(個人向け
#!/usr/bin/env bash
#
# 撮って出しJPEG整理スクリプト
#
# 写真ディレクトリの構造 (raw の位置は任意の深さで良い):
# SOURCE_ROOT/
# 2026/06/19/ <- 日付ディレクトリ (= raw の親)
# DSC0001.JPG <- 撮って出しJPEG (日付ディレクトリ直下)
# DSC0002.JPG
# raw/ <- RAW + メタデータ
# DSC0001.ARW
# DSC0001.xmp
# ...
#
# 処理内容:
# SOURCE_ROOT 以下を再帰的に走査し、「raw ディレクトリ」を見つける。
# raw の存在をトリガーとし、その親を日付ディレクトリとして次を行う:
# 1. 日付ディレクトリ直下の撮って出しJPEGを、SOURCE_ROOT からの相対パスを
# 保ったまま DEST_ROOT/<相対パス>/ へ移動する。
# 2. raw/ の中身を全て直上 (日付ディレクトリ) へ移動する。
# 3. 空になった raw/ ディレクトリを削除する。
# 1ファイル移動する毎にログを出力する。
#
# 移動先に同名ファイルが既に存在した場合はエラーで中断する。
set -euo pipefail
usage() {
cat >&2 <<EOF
Usage: $(basename "$0") [-n|--dry-run] <SOURCE_ROOT> <DEST_ROOT>
SOURCE_ROOT 日付ディレクトリが並んでいる写真ディレクトリ
DEST_ROOT 撮って出しJPEGの移動先ディレクトリ
-n, --dry-run 実際には移動/削除せず、行う操作だけをログ出力する
EOF
exit 2
}
DRY_RUN=0
positional=()
while [[ $# -gt 0 ]]; do
case $1 in
-n|--dry-run) DRY_RUN=1; shift ;;
-h|--help) usage ;;
--) shift; while [[ $# -gt 0 ]]; do positional+=("$1"); shift; done ;;
-*) echo "ERROR: 不明なオプション: $1" >&2; usage ;;
*) positional+=("$1"); shift ;;
esac
done
[[ ${#positional[@]} -eq 2 ]] || usage
SOURCE_ROOT=${positional[0]%/} # 末尾スラッシュを除去 (相対パス算出のため)
DEST_ROOT=${positional[1]%/}
[[ -d $SOURCE_ROOT ]] || { echo "ERROR: SOURCE_ROOT がディレクトリではありません: $SOURCE_ROOT" >&2; exit 1; }
# 撮って出しJPEGと判定する拡張子 (大文字小文字は区別しない)
shopt -s nullglob nocaseglob
# dry-run 時はログ行の先頭に印を付ける
PREFIX=""
[[ $DRY_RUN -eq 1 ]] && PREFIX="[DRY-RUN] "
log() { printf '%s %s%s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$PREFIX" "$*"; }
# 移動先に同名ファイルがあれば中断、なければ mv してログ出力する
# (dry-run 時は移動せずログのみ。衝突チェックは実行する)
move_file() {
local src=$1 dst=$2
if [[ -e $dst ]]; then
echo "ERROR: 移動先に同名ファイルが既に存在します。中断します: $dst" >&2
exit 1
fi
[[ $DRY_RUN -eq 0 ]] && mv -- "$src" "$dst"
log "MOVED $src -> $dst"
}
jpeg_total=0
raw_total=0
dir_total=0
# raw ディレクトリの存在をトリガーにする。
# SOURCE_ROOT 以下を再帰的に走査し、名前が "raw" のディレクトリを全て見つける。
# (raw が無いディレクトリは対象の構造ではないので、自然と対象外になる)
while IFS= read -r -d '' raw_dir; do
date_dir=$(dirname "$raw_dir")
# SOURCE_ROOT からの相対パス (例: 2026/06/19)。構造保持のため移動先で再現する。
rel_dir=${date_dir#"$SOURCE_ROOT"/}
[[ $rel_dir == "$date_dir" ]] && rel_dir="." # date_dir が SOURCE_ROOT 直下の場合
log "==== 処理開始: $rel_dir (raw: $raw_dir) ===="
((dir_total++)) || true
# --- 1. 撮って出しJPEG を DEST_ROOT/<相対パス> へ移動 ---
jpeg_dest_dir="$DEST_ROOT/$rel_dir"
jpegs=("$date_dir"/*.jpg "$date_dir"/*.jpeg)
if [[ ${#jpegs[@]} -gt 0 ]]; then
[[ $DRY_RUN -eq 0 ]] && mkdir -p -- "$jpeg_dest_dir"
for jpg in "${jpegs[@]}"; do
move_file "$jpg" "$jpeg_dest_dir/$(basename "$jpg")"
((jpeg_total++)) || true
done
else
log "撮って出しJPEGなし: $rel_dir"
fi
# --- 2. raw/ の中身を直上 (日付ディレクトリ) へ移動 ---
raw_entries=("$raw_dir"/* "$raw_dir"/.[!.]* "$raw_dir"/..?*)
for entry in "${raw_entries[@]}"; do
move_file "$entry" "$date_dir/$(basename "$entry")"
((raw_total++)) || true
done
# --- 3. 空になった raw/ を削除 ---
# dry-run 時は中身を移動していないため rmdir せずログのみ
[[ $DRY_RUN -eq 0 ]] && rmdir -- "$raw_dir"
log "REMOVED raw ディレクトリ: $raw_dir"
done < <(find "$SOURCE_ROOT" -depth -type d -name raw -print0)
log "==== 完了: 対象 ${dir_total} ディレクトリ / JPEG ${jpeg_total} 件, raw ${raw_total} 件を移動しました ===="
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment