みなさん大掃除は済みましたか? 自分は今パソコンの中を大掃除中です。
今年たくさん写真とったおかげでMACのディスクをかなり圧迫していてちょうどそれの整理をしています。
自分のカメラは1枚の写真に対してORFとJPGファイルを2つ生成するような設定となっています。 ただ、ORFファイルがあればJPGは要らないな〜と思ったので今回まとめて整理出来るスクリプトを書きました。
ディレクトリを引数にとってそのディレクトリ以下を探索して、
JPGとORFファイルを重複して持っているものは削除するというものです。
package main import ( "fmt" "os" "path/filepath" "regexp" // "os" "flag" "log" "os/exec" ) const ( DEBUG = false EXTENSION = ".JPG" WALK_PATH = "/Users/hogehoge/Dropbox/Pictures/写真 Library.photoslibrary/" TRASH_BOX = "~/.Trash" ) const raw = ` on run argv tell application "Finder" repeat with f in argv move (f as POSIX file) to trash end repeat end tell end run ` var trash = filepath.Join(os.Getenv("HOME"), ".Trash") func go2Trash(f string) error { bin, err := exec.LookPath("osascript") if err != nil { err = fmt.Errorf("not yet supported") return err } if _, err = os.Stat(trash); err != nil { err = fmt.Errorf("not yet supported") return err } path, err := filepath.Abs(f) if err != nil { return err } params := []string{"-e", raw, path} cmd := exec.Command(bin, params...) if err = cmd.Run(); err != nil { return err } return nil } func WalkFunc(path string, info os.FileInfo, err error) error { if err != nil { fmt.Println(err) return nil } if info.IsDir() { return nil } if ext := filepath.Ext(path); ext == EXTENSION { pat, err := regexp.Compile(EXTENSION + "$") if err != nil { fmt.Println(err) return nil } orfpath := pat.ReplaceAllString(path, ".ORF") if _, berr := os.Stat(orfpath); berr == nil { fmt.Println("ORF File Exist: ", path) if dryrun { // if dry-run mode, file isn't deleted. log.Println("next file will be deleted: ", path) return nil } // File Remove Process if rename { derr := go2Trash(path) if derr != nil { log.Println(err) return err } } else { derr := os.Remove(path) if derr != nil { log.Println(err) return err } } } } return nil } var path string var rename, dryrun bool func init() { flag.StringVar(&path, "path", WALK_PATH, "Pictures filepath.") flag.BoolVar(&dryrun, "n", false, "dry run flag") flag.BoolVar(&rename, "trash", true, "go to trashbox") flag.Parse() debugp(fmt.Sprintf("dryrun: %s", dryrun)) debugp(fmt.Sprintf("trash: %s", rename)) if path != WALK_PATH { tmp_p, err := filepath.Abs(path) if err != nil { log.Fatalln(err) } path = tmp_p } debugp(path) } func debugp(debugObj interface{}) { if DEBUG { fmt.Println(debugObj) } } func main() { f := WalkFunc err := filepath.Walk(path, f) if err != nil { fmt.Println(err) } }
機能は以下のとおり。
- ドライラン
- ゴミ箱に入れずに直接削除モード
あとはこのスクリプトをビルドしてドライランで削除されるファイルを確認。 問題がなければドライランオプションを外して削除という流れです。
$ go build -o walker $ ./walker -path=~/Dropbox/Pictures/写真\ Library.photoslibrary -n <中略> $ ./walker -path=~/Dropbox/Pictures/写真\ Library.photoslibrary 〜〜〜〜〜〜 ORF File Exist: /path/to/2015/09/20/20150920-181504/P9200882.JPG ORF File Exist: /path/to/2015/09/20/20150920-181504/P9200883.JPG ORF File Exist: /path/to/2015/09/20/20150920-181504/P9200886.JPG ORF File Exist: /path/to/2015/09/20/20150920-181504/P9200889.JPG 〜〜〜〜〜〜
こんなスクリプトでもうまく動きましたが実行してみてると1つ課題が見つかりました。
コマンド実行でゴミ箱に送ってる部分が遅いのです。
ファイル1000個ぐらいで15分程度なので耐えられない遅さではないとは思いますが、
go で並列化出来るといいんだろうなと感じました。
余談ですが、ゴミ箱に入れる方法が分からなかったのでその部分は gomi
を参考にさせてもらいました。
(AppleScript使って実現してるんですね。)