趣味で写真をたくさん撮っていますが、手動のリネーム操作を自動化するスクリプトを作成しました。その際のTipsです
やりたいこと
デジカメのSDカードから今日撮影した写真をPCにコピーする
コピーのついでに日付と連番を含むファイル名に変更する
完成したスクリプト(改良版)
mkdir ~/Desktop/$(date "+%Y%m%d");ls -l -D'%Y%m%d' /Volumes/EOS_DIGITAL/DCIM/*/*.JPG |awk '$6=='$(date "+%Y%m%d")' {line = line + 1; printf "cp -p %s ~/Desktop/%s/EOSR6_%s_%06d.jpg\n", $7, $6,$6,line}'|sh
改良したポイント
処理の流れはls
とawk
という簡素なものになりました
ls
のファイル名に「*」を記述しました
これで、デジカメのフォルダが複数にまたがる場合もOKです
具体的には、100CANON、101CANONなど同時にリストアップできます
なお「*」にすることで、ファイル名のリストアップがフルパスになり扱い易くなります
awk
の{}
で囲まれたアクション部分でline = line + 1
とすることで
抽出したものだけ連番をつけることができます
NRだと処理ごとなので、全件の連番となります
以前の記事も、下記にそのまま残しておきます
完成したスクリプト
試行錯誤の結果こんなスプリプとになりました
mkdir ~/Desktop/$(date "+%Y%m%d");find /Volumes/EOS_DIGITAL/DCIM/100CANON -newermt $(date "+%Y%m%d") | xargs -J% ls -l -D '%Y%m%d' %|sort -k6| awk '{ printf "cp -p %s ~/Desktop/%s/EOSR6_%s_%06d.jpg\n", $7, $6,$6,NR }'|sh
説明
まず大きな流れです
mkdirで保存用フォルダ作成
findでSDカードから本日撮影したファイルを抽出
抽出したファイルの作成日でソート
awkでリネーム用のcpコマンドを作成
cpコマンドの実行
以下解説です
mkdirで保存用フォルダ作成
mkdir ~/Desktop/$(date "+%Y%m%d");
コピー先用フォルダとして日付(yyyymmdd)としてデスクトップに作成します
ちなみに1日前の日付で作成したい場合は下記のようにdateコマンドの-vオプションで記述します
$(date -v-1d "+%Y%m%d")
findでSDカードから本日撮影したファイルを抽出
find /Volumes/EOS_DIGITAL/DCIM/100CANON -newermt $(date "+%Y%m%d")
-newermtオプションは指定日時よりも更新が新しいものを抽出するオプションです
日付だけ指定しているので0:00以降のものが抽出されます
ちなみに検索対象のフォルダ名は、ターミナルに対象フォルダをドロップすると文字として取得できます
なお、抽出される結果はファイル名(フルパス)となります
ここから先はパイプで処理を連携します
抽出したファイルの更新日でソート
| xargs -J% ls -l -D '%Y%m%d' %|sort -k6
xargsの-J%オプションはパイプで受け渡された項目を、xargsに続けるコマンド(今回はls)に%として展開できます
上の例ではlsの対象ファイルとなります
普通lsはファイルの一覧を表示させるもので、1ファイルを指定して情報をみることはあまりないかもしれません
そういう意味では1ファイルごとにlsをしているので非効率な気もします。。。
それはともかくlsを見てみましょう
更新日でソートするためにfindで抽出したファイルをlsの-lオプションで情報を取得します
-D '%Y%m%d'
は出力する日付のフォーマットを指定するものです
デフォルトでは当日更新分は"hh:mm"となったり、昨日のものが"昨日"という相対表示となっています
最後はsortコマンドです
sortの-kオプションはキーフィールドの指定です
6とあるのは6番目をキーとするという意味です
Ls -lで表示される6項目(更新日)を使ってソートます
Lsの表示上は更新日だけですが、タイムスタンプとしてソートするので撮影順になります
awkでリネーム用のcpコマンドを作成
awk '{ printf "cp -p %s ~/Desktop/%s/EOSR6_%s_%06d.jpg\n", $7, $6,$6,NR }'
awkはオークと読み、人名に由来する造語です
入力情報を抽出して出力するコマンドで高度な抽出や編集が可能です
今回のawkは入力をすべて出力するので抽出はありませあん
出力はprintfで、ダブルクォーテーション内は出力フォーマットで、後続のコンマ以降で項目を指定します
ダブルクォーテーション内の%〜が可変項目となります
具体的には
1つ目の可変項目は%s(文字列)で、内容は$7
。即ち、インプット情報(ls)の7項目目=ファイル名
2つ目は%s(文字列)で、内容は$6
。即ち、インプット情報(ls)の6項目目=更新日
3つ目も%s(文字列)で、内容は$6
。即ち、インプット情報(ls)の6項目目=更新日
最後は%06d(6桁のゼロ埋め数字)で、内容はNR
。これはawkの変数でインプットの件数となります
もっと簡素化できるかも
ここで疑問がわきます
Awkで抽出できるならlsとawkだけでよいのではないかと
実際にかいてみました
mkdir ~/Desktop/$(date "+%Y%m%d");ls -l -D'%Y%m%d' /Volumes/EOS_DIGITAL/DCIM/100CANON |awk '$6=='$(date "+%Y%m%d")' {printf "cp -p /Volumes/EOS_DIGITAL/DCIM/100CANON/%s ~/Desktop/%s/EOSR6_%s_%06d.jpg\n", $7, $6,$6,NR}'|sh
全件出力ではないのでコピー後の連番が飛ぶことがあります
そのためはじめにfindで抽出しているのです
→改良版として簡素化できました(このページの先頭を参照)
参考サイト
DevelopersIO
大量のファイルをシェルのコマンドで一括リネームする
UNIX & Linux コマンド・シェルスクリプト リファレンス
awkリファレンス