많은 파일이 포함된 디렉토리가 있습니다. 모든 파일은 동일한 패턴을 가지고 있습니다 <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는 한 달에 한 번 또는 때로는 매년 새 파일을 받기 때문에 사용할 수 없습니다 .
내 생각은 ID를 기준으로 파일 이름을 그룹화하고 마지막 항목을 유지하지 않는 것입니다. Bash를 사용하여 이 문제를 어떻게 해결할 수 있나요?
답변1
여기서는 bash가 특별히 필요하지 않습니다. sh
위치 배열을 두 번 활용하면 간단한 스크립트로 이를 수행할 수 있습니다. 외부 루프는 필요한 모든 데이터 파일(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
, 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의 대안이 있습니다. 파일을 두 번 반복할 필요는 없습니다.
#!/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)