質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

89.12%

日付が連続しているファイルの欠番を一日前のファイルを用いて埋めたい

解決済

回答 2

投稿

  • 評価
  • クリップ 0
  • VIEW 209

momokoko

score 16

ディレクトリ構造 

$ ls -1 cham-arayaminami-high/202002230102分.jpg
202002240102分.jpg
202002260102分.jpg
202002270102分.jpg
~ 
202006101206分.jpg

抜けている日付を前の日の画像を複製し、補完したいです。
また、Exif情報の撮影された日時(DateTimeOriginal)を前の日のものではなく補完後のものと合わせたいです。
抜けている日付は数日間あるものをあります。

目的が達成できれば、シェルスクリプトでもpythonでも構いません。
ネットでも探しても似たような記事すら検索にかからず困っております。
ご教授頂けたら嬉しいです。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • hidezzz

    2020/06/11 01:40

    補完して作成したファイルの時刻部分はどうなれば良いですか?(00時00分で良いですか?)

    キャンセル

  • momokoko

    2020/06/11 01:42

    質問ありがとうございます!
    時刻は問いません。

    キャンセル

回答 2

checkベストアンサー

0

python版を作って見ました(file_comp.py)。
外部ツールとしてExiftoolを必要とします。
同じ日のファイルが2つ以上存在するとエラーになります。

import argparse
import pathlib
import pandas as pd
from shutil import copyfile

FILENAME_FORMAT = "%Y年%m月%d日%H時%M分.jpg"


def update_exif(filename, exif_datetime):
    import subprocess

    args = [
        "exiftool",
        "-overwrite_original",
        "-DateTimeOriginal={}".format(
            exif_datetime.strftime("%Y:%m:%d %H:%M:%S")
        ),
        filename,
    ]
    subprocess.Popen(args, stdout=subprocess.DEVNULL)


def main():
    parser = argparse.ArgumentParser()
    parser.add_argument("dirname")
    args = parser.parse_args()

    # ファイルリストを作成
    p = pathlib.Path(args.dirname)
    filenames = []
    for pathname in p.iterdir():
        try:
            pd.to_datetime(pathname.name, format=FILENAME_FORMAT)
            filenames.append(pathname.name)
        except ValueError:
            pass
    filenames.sort()

    # 日付をインデックスに持つDataFrameを作成
    df = pd.DataFrame({"src_filename": filenames})
    df["datetime"] = pd.to_datetime(filenames, format=FILENAME_FORMAT)
    df.index = pd.DatetimeIndex(df.datetime.dt.date)
    df.index.name = "date"

    # 1日でリサンプリング
    df = df.asfreq(freq="1D")

    # 存在しない日付は前の日のファイルを複製
    df.src_filename.fillna(method="ffill", inplace=True)

    # EXIFに埋め込む時刻は日付+00:00:00
    df["exif_datetime"] = df.datetime
    df.exif_datetime.fillna(df.index.to_series(), inplace=True)

    # 出力するファイル名を作成
    df["dst_filename"] = df.exif_datetime.dt.strftime(FILENAME_FORMAT)

    df_target = df[df.datetime.isnull()]
    # デバッグ用
    print(df_target[["src_filename", "dst_filename", "exif_datetime"]])

    # 処理対象のみ抽出して複製
    for _, row in df_target.iterrows():
        src = p / row.src_filename
        dst = p / row.dst_filename
        copyfile(src, dst)
        update_exif(dst, row.exif_datetime)


if __name__ == "__main__":
    main()

実行は引数にディレクトリを渡します。
実行すると新たに作成したファイルの一覧が表示されます。

$ tree cham-arayaminami-high/
cham-arayaminami-high/
├── 202002210102分.jpg
├── 202002230202分.jpg
└── 202003010102分.jpg

$ python file_comp.py cham-arayaminami-high/
                     src_filename           dst_filename exif_datetime
date                                                                  
2020-02-22  202002210102分.jpg  202002220000分.jpg    2020-02-22
2020-02-24  202002230202分.jpg  202002240000分.jpg    2020-02-24
2020-02-25  202002230202分.jpg  202002250000分.jpg    2020-02-25
2020-02-26  202002230202分.jpg  202002260000分.jpg    2020-02-26
2020-02-27  202002230202分.jpg  202002270000分.jpg    2020-02-27
2020-02-28  202002230202分.jpg  202002280000分.jpg    2020-02-28
2020-02-29  202002230202分.jpg  202002290000分.jpg    2020-02-29

$ tree cham-arayaminami-high/
cham-arayaminami-high/
├── 202002210102分.jpg
├── 202002220000分.jpg
├── 202002230202分.jpg
├── 202002240000分.jpg
├── 202002250000分.jpg
├── 202002260000分.jpg
├── 202002270000分.jpg
├── 202002280000分.jpg
├── 202002290000分.jpg
└── 202003010102分.jpg

$ exiftool -n -DateTimeOriginal cham-arayaminami-high/*.jpg 
======== cham-arayaminami-high/2020年02月21日01時02分.jpg
Date/Time Original              : 2020:06:10 14:35:34
======== cham-arayaminami-high/2020年02月22日00時00分.jpg
Date/Time Original              : 2020:02:22 00:00:00
======== cham-arayaminami-high/2020年02月23日02時02分.jpg
Date/Time Original              : 2020:06:10 14:35:34
======== cham-arayaminami-high/2020年02月24日00時00分.jpg
Date/Time Original              : 2020:02:24 00:00:00
======== cham-arayaminami-high/2020年02月25日00時00分.jpg
Date/Time Original              : 2020:02:25 00:00:00
======== cham-arayaminami-high/2020年02月26日00時00分.jpg
Date/Time Original              : 2020:02:26 00:00:00
======== cham-arayaminami-high/2020年02月27日00時00分.jpg
Date/Time Original              : 2020:02:27 00:00:00
======== cham-arayaminami-high/2020年02月28日00時00分.jpg
Date/Time Original              : 2020:02:28 00:00:00
======== cham-arayaminami-high/2020年02月29日00時00分.jpg
Date/Time Original              : 2020:02:29 00:00:00
======== cham-arayaminami-high/2020年03月01日01時02分.jpg
Date/Time Original              : 2020:06:10 14:35:34
   10 image files read

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2020/06/12 04:13

    回答ありがとうございます!
    無事、ファイルが前日のもので複製されました!

    追加の質問になってしまい恐縮ですが、cham-arayaminami-highのようなディレクトリが70個ほどありfor文などで回して処理したいと考えていました。

    「./実行ファイル 引数(ディレクトリ)」という形で処理するのが初めてで、繰り返し処理ができるのかもよくわかっておりません。
    ググっても見つけることができなかったのですが、何かいい方法があったら教えていただきたいです。

    キャンセル

  • 2020/06/12 06:48

    findコマンドを使うのはどうでしょうか?
    例えばあるディレクトリA以下に
    A
    ├── 対象ディレクトリ1/
    ├── 対象ディレクトリ2/
    └── 対象ディレクトリ3/
    のような構造を持つ場合は、findコマンドで次のように一括処理できます。
    find A -type d -exec python file_comp.py {} \;

    キャンセル

  • 2020/06/15 12:00

    返信がおそくなりすみません。
    無事できました!
    ありがとうございました!

    キャンセル

0

AWKスクリプトを作ってみました。
重要な注意:必ずあらかじめ全体のバックアップを取ってください。
LinuxMint19.3(Ubuntu18.04LTSほぼ同等)で動作確認してます。
Exiftoolが別途必要です。
dateコマンドはGNU版が必要です。(Macの場合最初から入ってるdateだと動かないかも)

#! /usr/bin/awk -f
{
        # ファイル名から日付year,month,dayを取り出す。
        year = substr( $0, 1, 4 );
        month = substr( $0, 6, 2 );
        day = substr( $0, 9, 2 );

        # 年月日からシリアル秒serialsecを求める。
        "date -d " year "-"  month "-" day " +%s" | getline serialsec;

        # 連想配列(シリアル秒→ファイル名)を作る。
        days[ serialsec ] = $0;

        # 開始日付と終了日付を求める。
        if ( NR == 1 ) {
                start = serialsec;
                end = serialsec;
        }
        else {
                if ( start > serialsec ) {
                        start = serialsec;
                }
                if ( end < serialsec ) {
                        end = serialsec;
                }
        }
}
END {

        # 開始日付から終了日付までループする
        for ( t = start ; t <= end ; t += 86400 ) {

                # 画像ファイルが存在する?
                if ( t in days ) {
                        # 画像ファイルのファイル名を覚えておく。(抜けてる日付位置にはこのファイルをコピーする)
                        print "# " days[ t ];
                        last = days[ t ];
                }
                else {
                        # コピーを実行するコマンド文字列を出力する。
                        "date -d @" t " +'%Y年%m月%d日00時00分.jpg'" | getline fname;
                        print "cp -p " last " " fname
                        # Exifを書き換えるコマンドをするコマンド文字列を出力する。
                        "date -d @" t " +'%Y-%m-%d 00:00:00'" | getline date;
                        print "exiftool -DateTimeOriginal='" date "' " fname
                }
        }
}
(元ファイルとAWKスクリプト)
$ ls -l
-rw-r--r-- 1 hidezzz hidezzz 3555099  4月 26  2016 2016年04月26日12時00分.jpg
-rw-r--r-- 1 hidezzz hidezzz 3381213  4月 27  2016 2016年04月27日12時00分.jpg
-rw-r--r-- 1 hidezzz hidezzz 3474408  4月 29  2016 2016年04月29日12時00分.jpg
-rwxrwxr-x 1 hidezzz hidezzz    1352  6月 11 03:44 umeume.awk*

(実行されるコマンドの確認(まだこのコマンドでは実行されません))
$ ls -1 *.jpg | ./umeume.awk 
# 2016年04月26日12時00分.jpg
# 2016年04月27日12時00分.jpg
cp -p 2016年04月27日12時00分.jpg 2016年04月28日00時00分.jpg
exiftool -DateTimeOriginal='2016-04-28 00:00:00' 2016年04月28日00時00分.jpg
# 2016年04月29日12時00分.jpg

(末尾に「| sh」を付けて上記で表示されているコマンドを実際に実行)
$ ls -1 *.jpg | ./umeume.awk | sh
Warning: [minor] Overlapping MakerNotes values - 2016年04月28日00時00分.jpg
    1 image files updated

(補完されたファイルの確認)
$ ls -l *.jpg*
-rw-r--r-- 1 hidezzz hidezzz 3555099  4月 26  2016 2016年04月26日12時00分.jpg
-rw-r--r-- 1 hidezzz hidezzz 3381213  4月 27  2016 2016年04月27日12時00分.jpg
-rw-r--r-- 1 hidezzz hidezzz 3381219  6月 11 03:49 2016年04月28日00時00分.jpg
-rw-r--r-- 1 hidezzz hidezzz 3381213  4月 27  2016 2016年04月28日00時00分.jpg_original
-rw-r--r-- 1 hidezzz hidezzz 3474408  4月 29  2016 2016年04月29日12時00分.jpg

(Exif情報の確認)
$ exiftool -n -DateTimeOriginal 2016年04月28日00時00分.jpg*
======== 2016年04月28日00時00分.jpg
Date/Time Original              : 2016:04:28 00:00:00
======== 2016年04月28日00時00分.jpg_original
Date/Time Original              : 2016:04:26 17:28:24
    2 image files read

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2020/06/12 03:59

    バックアップを取って実行しました!

    下記のように書き換えました。
    "gdate -d " year "-" month "-" day " +%s" | getline serialsec;
    "gdate -d @" t " +'%Y年%m月%d日00時00分.jpg'" | getline fname;
    "gdate -d @" t " +'%Y-%m-%d 00:00:00'" | getline date;

    実行しましたがエラーが出てしまいました。
    ls -1 *.jpg | ./umeume.awk
    gdate: invalid date ‘2020-\271\264-2\346’
    gdate: invalid date ‘2020-\271\264-4\346’
    gdate: invalid date ‘2020-\271\264-5\346’
    gdate: invalid date ‘2020-\271\264-6\346’
    # 2020年06月09日01時06分.jpg

    キャンセル

  • 2020/06/12 09:39

    マルチバイト文字(日本語文字)が認識してないような気がします。
    $ export LANG=ja_JP
    $ export LANG=ja_JP.UTF-8
    あたりを実行してからスクリプトを実行するとどうなりますか?
    別の方の回答で解決しているようなので時間が空いたときにでもどうぞ

    キャンセル

  • 2020/06/15 12:01

    返信ありがとうございます!
    返信おそくなりました。
    いま仕事中でできませんが、また時間ができたときにやってみます!

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 89.12%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる