ファイル削除 - ファイル名パターンに基づいて最新のファイルを保持

ファイル削除 - ファイル名パターンに基づいて最新のファイルを保持

多くのファイルを含むディレクトリがあります。すべてのファイルは同じパターンを持っています<id>_data_<date>.csv。私がしたいのは、すべてのファイルを削除し、それぞれの最新のファイルを維持することです<id>

例ディレクトリ:

10020077_data_2017-07-18_001.csv
10020078_data_2017-07-18_001.csv
10020209_data_2019-04-23_001.csv
10020209_data_2019-04-24_001.csv
10020209_data_2019-04-25_001.csv
10020209_data_2019-04-26_001.csv
10020209_data_2019-04-27_001.csv
10020209_data_2019-04-28_001.csv
10020272_data_2019-04-23_001.csv
10020272_data_2019-04-24_001.csv
10020272_data_2019-04-25_001.csv
10020272_data_2019-04-26_001.csv
10020272_data_2019-04-27_001.csv
10020272_data_2019-04-28_001.csv
10020286_data_2019-04-23_001.csv

予想される結果:

10020077_data_2017-07-18_001.csv
10020078_data_2017-07-18_001.csv
10020209_data_2019-04-23_001.csv <-- delete
10020209_data_2019-04-24_001.csv <-- delete
10020209_data_2019-04-25_001.csv <-- delete
10020209_data_2019-04-26_001.csv <-- delete 
10020209_data_2019-04-27_001.csv <-- delete
10020209_data_2019-04-28_001.csv
10020272_data_2019-04-23_001.csv <-- delete
10020272_data_2019-04-24_001.csv <-- delete
10020272_data_2019-04-25_001.csv <-- delete
10020272_data_2019-04-26_001.csv <-- delete
10020272_data_2019-04-27_001.csv <-- delete
10020272_data_2019-04-28_001.csv
10020286_data_2019-04-23_001.csv

find -mtimeこの場合、一部のIDは毎日新しいファイルを受け取り、他のIDは月に1回、または時には毎年新しいファイルを受け取るため使用できません。

私の考えは、IDに基づいてファイル名をグループ化し、最後のエントリを保持しないことです。 Bashを使用してこの問題をどのように解決できますか?

答え1

ここでは、bashは特に必要ありません。sh位置配列を2回利用すると、簡単なスクリプトでこれを行うことができます。外部ループは、必要なすべてのデータファイル(IDと日付部分のワイルドカード)を取得します。 ID部分を抽出し、そのIDを持つすべてのファイルを繰り返すサブシェルを起動します。その後、サブシェルはこれらのファイルの自然な日付順のリストを繰り返し、最新のファイルを保持しながら最後のファイルを除くすべてのファイルを削除します。

#!/bin/sh

set -- *_data_*.csv
for f in "$@"
do
  id=${f%%_*}
  # a subshell so we don't clobber $@
  (
        set -- "${id}"_data_*.csv
        while [ "$#" -gt 1 ]
        do
          rm -- "$1"
          echo "DELETE: $1"
          shift
        done
  )
done

echo ... DELETE提供したファイル名の結果を表示できるように説明を追加しました。

DELETE: 10020209_data_2019-04-23_001.csv
DELETE: 10020209_data_2019-04-24_001.csv
DELETE: 10020209_data_2019-04-25_001.csv
DELETE: 10020209_data_2019-04-26_001.csv
DELETE: 10020209_data_2019-04-27_001.csv
DELETE: 10020272_data_2019-04-23_001.csv
DELETE: 10020272_data_2019-04-24_001.csv
DELETE: 10020272_data_2019-04-25_001.csv
DELETE: 10020272_data_2019-04-26_001.csv
DELETE: 10020272_data_2019-04-27_001.csv

答え2

もちろん、システムでmktemp、、、、、を使用できる限り、 1行teeのコマンドシーケンスを使用してこれを実行することもできます。そうでない場合は、次のように置き換えることができます。sortgrepxargsrmtacsort -r

(temp_all=$(mktemp) && temp_last=$(mktemp) && { tac | tee $temp_all | sort -un > $temp_last ; } && grep -vf $temp_last $temp_all ; rm -f $temp_last $temp_all)

上記のコマンドは、stdinの完全なファイルリスト(a find、an ls、aファイルなどの適切な方法で来ることができます)を取得し、削除するファイルのリストを表示します。その後、そのリストを次にパイプできます。xargs rm

分割:

(
temp_all=$(mktemp) && \
temp_last=$(mktemp) && \ # make a couple of temp files
{ 
    tac | \              # reverse the list of files and ...
    tee $temp_all | \    # pipe it into one temp entirely and also ...
    sort -un > $temp_last ; \ # into a sort that makes names unique into the other temp
} && \
    grep -vFf $temp_last $temp_all ; \ # use grep to filter out names
rm -f $temp_last $temp_all  # remove temp files
)

これは入力名の数に関係なく処理できますが、名前に改行文字を含めないでください。これはあなたの場合に合理的に見えます。

答え3

Put all file names in l.txt
Proceed with below steps and it worked fine

da=`awk -F "_" '{print $3}' l.txt | sort | uniq| sort -nr| sed -n '1p'`


 for id in `awk -F "_" '{print $3}' l.txt | sort | uniq`
> do
> find  path -maxdepth 1 -type f -newermt $da -iname "$id*"  | sed -n '2,$p'| awk '{print "rm" " " $1}'| sh;done

答え4

私はすでに多くの答えがあることを知っていますが、ここにはPythonの代替案があります。ファイルを2回繰り返す必要はありません。

#!/usr/bin/env python                                                           

import os
import glob

if __name__ == '__main__':
    newest_dict = dict()

    for f in glob.glob('*.csv'):
        id = f[:8]

        if id not in newest_dict:
            newest_dict[id] = f
        else:
            nf = newest_dict[id]

            f_ts = f[14:24]
            nf_ts = nf[14:24]

            if f_ts > nf_ts:
                newest_dict[id] = f
                print("Deleting", nf)
                os.remove(nf)                                                  
            else:
                print("Deleting", f)
                os.remove(f)

関連情報