awkでファイル名とタイムスタンプを変更するスクリプトを作る

目次

公開日 2022-07-09 更新日 2023-04-24

スクリーンショットのファイル名を短縮する

例えば、このようにしたい。

Screenshot from 2022-07-01 22-14-47.png
  ⇩
dv220701_221447.png

jpgならファイル中にタグを作って作成日時を埋め込めますが、pngではできません。GUIでコピーや移動する場合にタイムスタンプをコントロールするのは難しいことです。ファイル名に日時を記録しておくのが確実です。

どこかにスクリーンショットの名前のルールの設定があるのかもしれなませんが、とりあえず、すでにあるファイル名をawkなどでスクリプトを作って変更しました。学んだことを記録しておきます。

フィールドセパレータに複数の文字を指定する

結論を先にいうと次のうちどれか

awk -F'[ -]'   ' 'か'-'をひとつずつ
awk -F' |-'    ' 'か'-'をひとつずつ(|は文字列を指定できる)
awk -F' +|-'   ' 'の連続か'-'のひとつのどちらか
awk -F'[ -]+'  ' 'か'-'の連続

If FS is a single character, fields are separated by that character. If FS is the null string, then each individual character becomes a separate field. Otherwise, FS is expected to be a full regular expression. In the special case that FS is a single space, fields are separated by runs of spaces and/or tabs and/or newlines.

  1. 一文字の指定の時は、その文字で区切る。(-F'.' はピリオドで区切る)
  2. ヌル文字列では個々の文字がフィールドとなる。(ヌル文字を指定する方法が不明。-F''ではできない)
  3. その他は、正規表現と解釈される。(-F' +|,+'は一つ以上の' 'または一つ以上の',' -F'[ ,]+'は' 'または','の一つ以上の繰り返し)
  4. 特別な場合として' 'が指定されている場合、スペースやタグや改行の連続したもので区切られる(連続しても一つとみなす)(デフォルト)

'.'は正規表現では任意の文字だが、-F'.'や -F'[ .]'ではピリオドを意味する。

awkのprintfでシングルクオートの出力

ファイル名にスペースを含むので、''で囲む必要がある。

\047$0\047

""ならば

\042$0\042

mv を使ってファイル名を変更する

2022を22にするために22は直接文字を書きました。

$ ls  |awk -F'-| ' '{printf "mv \047%s\047 dv22%s%s_%s%s%s\n",$0,$4,$5,$6,$7,$8}'>>zz

作られるzzの内容は

mv 'Screenshot from 2022-07-01 22-14-47.png' dv220701_221447.png
mv 'Screenshot from 2022-07-01 22-17-54.png' dv220701_221754.png
mv 'Screenshot from 2022-07-01 22-18-58.png' dv220701_221858.png
mv 'Screenshot from 2022-07-01 22-19-02.png' dv220701_221902.png
....

これを使ってファイル名を書き換えるなら

$ . zz

別解: mv の代わりに cp -a を使う

タイムスタンプが変わらないようにするにはmvがよいのだが、コピーしてから元を消すということをやってしまうことも考えられる。確実なのは cp -a としておいて後で消すという方法だろう。これだとスクリプトができてから、コピー先を変更して日別に分けたりすることも可能になる。

$ ls *.png |awk -F'-| ' '{printf "cp -a \047%s\047 ../d0701sc/dv22%s%s_%s%s%s\n",$0,$4,$5,$6,$7,$8}'>zzz

作られるzzzの内容は

cp -a 'Screenshot from 2022-07-01 22-14-47.png' ../d0701sc/dv220701_221447.png
cp -a 'Screenshot from 2022-07-01 22-17-54.png' ../d0701sc/dv220701_221754.png
cp -a 'Screenshot from 2022-07-01 22-18-58.png' ../d0701sc/dv220701_221858.png
....

これを使ってファイル名を書き換えるなら

$ . zzz

タイムスタンプ確認

GUIでコピーしていたのですでにタイムスタンプが更新されていました。せっかく cp -a を思い出したのに残念。

そこでタイムスタンプを変更します。まず現在のタイムスタンプは次のようになっています。

$ ls -l *.png |head
-rwxrwxrwx 1 adachi adachi  54533  7月  6 16:54 dv220701_221447.png
-rwxrwxrwx 1 adachi adachi  76244  7月  6 16:54 dv220701_221754.png
-rwxrwxrwx 1 adachi adachi  79303  7月  6 16:54 dv220701_221858.png
-rwxrwxrwx 1 adachi adachi  79907  7月  6 16:54 dv220701_221902.png
-rwxrwxrwx 1 adachi adachi 134753  7月  6 16:54 dv220701_222025.png

rwxrwxrwxなのはNTFSの3.5インチポータブルHDDのファイルだから。

statを使って詳細がわかります。ls -l で出てくるのはModify:の部分です。

$ stat dv220701_221447.png
  File: dv220701_221447.png
  Size: 54533     	Blocks: 107        IO Block: 4096   通常ファイル
Device: 38h/56d	Inode: 141         Links: 1
Access: (0777/-rwxrwxrwx)  Uid: ( 1000/  adachi)   Gid: ( 1000/  adachi)
Access: 2022-07-06 16:54:38.000000000 +0900
Modify: 2022-07-06 16:54:34.000000000 +0900
Change: 2022-07-06 16:54:34.000000000 +0900
 Birth: -

scp を使うなら

sshを使ってネットワーク内のPCにコピーする場合は、scpを使います。

Ubuntuだとfumita.localなどでLAN内のPCを指定できます。

cpとはオプションが異なります。

scp -p *.png  fumita.local:/media/adachi/S1T/....

-r Recursively copy entire directories.

-p Preserves modification times, access times, and modes from the original file.

タイムスタンプ変更

touchが使えます。

touch -t STAMP     :STAMPの書式は [[CC]YY]MMDDhhmm[.ss]
touch -d STRING    :STRINGの書式はたとえば 2022-07-06 16:54:38

今回の場合、手持ちのファイルにある日時の書式から使えるものはないかと探ってみる。

#x(使えない) touch -d "2022-07-01 22-14-47" dv220701_221447.png 
#o(使える)   touch -d "2022-07-01 22:14:47" dv220701_221447.png 
#x(使えない) touch -d "220701_221447" dv220701_221447.png 
#o(使える)   touch -t "2207012214.47" dv220701_221447.png 

zzの内容を再掲すると

mv 'Screenshot from 2022-07-01 22-14-47.png' dv220701_221447.png
mv 'Screenshot from 2022-07-01 22-17-54.png' dv220701_221754.png
mv 'Screenshot from 2022-07-01 22-18-58.png' dv220701_221858.png
mv 'Screenshot from 2022-07-01 22-19-02.png' dv220701_221902.png
....

第一案

$ cat zz |awk -F'[- .]' '{printf "touch -d \047%s/%s/%s %s:%s:%s\047 %s.png\n",$4,$5,$6,$7,$8,$9, $11}'

つまり、

$1 $2_________ $3__ $4__ $5 $6 $7 $8 $9 $10_ $11____________ $12 
mv 'Screenshot from 2022-07-01 22-14-47.png' dv220701_221447.png

第二案

$ cat zz |awk -F'-| |.png' '{printf "touch -d \047%s/%s/%s %s:%s:%s\047 %s.png\n",$4,$5,$6,$7,$8,$9, $11}'

今度は、

$1 $2_________ $3__ $4__ $5 $6 $7 $8 $9    X $11____________
mv 'Screenshot from 2022-07-01 22-14-47.png' dv220701_221447.png

正規表現で文字候補を表す[ ]内ではピリオドはただのピリオドですが、複数の文字列の候補を表す | を使う場合はピリオドは任意文字になりますのでうまく行かなくなります。そこでpngをつけてpngの前に任意の文字があるものとして'.png'を区切りとして使います。$10は書けないのでXに変えていますが、これはシングルクォートになります。

どちらにしても、端末に出力されますから、うまく行くようになったら末尾に >zz2 などと適当なファイルに書き出して、

$ . zz2

としてスクリプトを実行します。

zz2は以下のような内容になります。

touch -d '2022/07/01 22:14:47' dv220701_221447.png
touch -d '2022/07/01 22:17:54' dv220701_221754.png
touch -d '2022/07/01 22:18:58' dv220701_221858.png
....

再びタイムスタンプ確認

$ stat dv220703_173324.png 
  File: dv220703_173324.png
  Size: 112534    	Blocks: 224        IO Block: 4096   通常ファイル
Device: 805h/2053d	Inode: 5017960     Links: 1
Access: (0644/-rw-r--r--)  Uid: ( 1000/  adachi)   Gid: ( 1000/  adachi)
Access: 2022-07-06 19:38:43.797390857 +0900
Modify: 2022-07-03 17:33:24.000000000 +0900
Change: 2022-07-06 19:29:47.711476015 +0900
 Birth: -