多くのファイルを含むディレクトリがあります。すべてのファイルは同じパターンを持っています<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
のコマンドシーケンスを使用してこれを実行することもできます。そうでない場合は、次のように置き換えることができます。sort
grep
xargs
rm
tac
sort -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)