スマホなどで撮影した画像をPCに取り込んだとき、取り込み日時がファイルの作成日時として設定されてしまい、撮影日時順で並べ替えができなくて不便だったりするので。
$ find . -maxdepth 1 -name '*.jpeg' -print0 | xargs -0 -I @ sh -c "sips -g creation '@' | sed -e '1d' | awk '{print \$2,\$3}' | sed -E 's/([0-9]+):([0-9]+):([0-9]+) ([0-9]+):([0-9]+):([0-9]+)/\\1\\2\\3\\4\\5.\\6/g' | xargs -I TS touch -t TS '@'"
これでカレントディレクトリの *.jpeg
ファイルすべての作成日時を撮影日時に変更することができる。もっと短く書ける方法が知りたい・・・。
以下、解説。
撮影日時の取得
まずはすべてのJPGファイルの撮影日時を取得してみようと思った。
$ for file in `find . -maxdepth 1 -name '*.jpeg'`; do
sips -g creation "$file" | sed -e '1d'
done
これで概ねOKなのだけど、ファイル名にスペースが含まれていると、forに渡されるときにファイル名が分割されてしまう。たとえば、 IMG_1234 (1).jpeg
というファイルがあると、次のように別々に処理されることになる。そして警告がでる。
sips -g creation "IMG_1234" | sed -e '1d'
sips -g creation "(1).jpeg" | sed -e '1d'
すこし調べたところ、for
をつかっている限りこれは解消できなそうだったので、xargs
を使った方法を模索する。 find
の出力をスペースではなくnull文字区切りにし、xargs
側もnull文字を区切りとして認識するようオプション指定。xargs
で実行するコマンド内にパイプが含まれているのでsh -c
でコマンド実行する。
$ find . -maxdepth 1 -name '*.jpeg' -print0 | xargs -0 -I @ sh -c "sips -g creation '@' | sed -e '1d'"
creation: 2000:01:02 11:22:33
creation: 2000:01:02 11:22:44
creation: 2000:01:02 11:22:55
...
touch
の仕様に合わせて日付フォーマット変更
ファイルの作成日時変更にはtouch
をつかう。作成日を変更前より未来の日時に変更することはできないみたいだけど、画像ファイルの作成日時が撮影日時より過去になっていることはないはずなので実用上問題はないと思う。
日時は、次のようなyyyyMMddHHmm.ss
形式でなくてはならないけれど、sips
コマンドは撮影日時を2000:01:02 11:22:33
みたいな形式で出してくるので、フォーマットの変換が必要。
$ touch -t 200001021122.33 IMG_1234.jpeg
sed
で正規表現をつかって次のように書いてみた。ここがもう少しシンプルになればよいのだけど。
$ echo -n ' creation: 2000:01:02 11:22:33' | awk '{print $2,$3}' | sed -E 's/([0-9]+):([0-9]+):([0-9]+) ([0-9]+):([0-9]+):([0-9]+)/\1\2\3\4\5.\6/g'
これをsh -c
の中に組み込み。バックスラッシュはエスケープが必要になる。
$ find . -maxdepth 1 -name '*.jpeg' -print0 | xargs -0 -I @ sh -c "sips -g creation '@' | sed -e '1d' | awk '{print \$2,\$3}' | sed -E 's/([0-9]+):([0-9]+):([0-9]+) ([0-9]+):([0-9]+):([0-9]+)/\\1\\2\\3\\4\\5.\\6/g'"
最後にtouch
。パイプで送られてくる文字列をタイムスタンプとしてオプションに指定する必要があるので、ここでもxargs
を使う。下記のような感じ。
$ echo '200001021122.33' | xargs -I TS touch -t TS IMG_1234.jpeg
これもsh -c
の中に組み込むと、最初に紹介したコマンドが完成する。
find . -maxdepth 1 -name '*.jpeg' -print0 | xargs -0 -I @ sh -c "sips -g creation '@' | sed -e '1d' | awk '{print \$2,\$3}' | sed -E 's/([0-9]+):([0-9]+):([0-9]+) ([0-9]+):([0-9]+):([0-9]+)/\\1\\2\\3\\4\\5.\\6/g' | xargs -I TS touch -t TS '@'"
touch
でうまくいかないときのためのSetFile
利用バージョン
find . -maxdepth 1 -name '*.jpeg' -print0 | xargs -0 -I @ sh -c "sips -g creation '@' | sed -e '1d' | awk '{print \$2,\$3}' | sed -E 's/([0-9]+):([0-9]+):([0-9]+) ([0-9]+):([0-9]+):([0-9]+)/\\2\\/\\3\\/\\1 \\4:\\5:\\6/g' | xargs -I TS SetFile -d 'TS' '@'"