특정 시간에 실행될 cronjob에 스크립트를 배치하고 파일 수가 60개를 초과하면 폴더에서 가장 오래된 파일을 삭제하고 싶습니다. 후입 선출법. 열심히 노력했는데,
#!/bin/ksh
for dir in /home/DABA_BACKUP
do
cd $dir
count_files=`ls -lrt | wc -l`
if [ $count_files -gt 60 ];
then
todelete=$(($count_files-60))
for part in `ls -1rt`
do
if [ $todelete -gt 0 ]
then
rm -rf $part
todelete=$(($todelete-1))
fi
done
fi
done
매일 저장되고 이름이 지정되는 백업 파일입니다 backup_$date
. 이거 괜찮아?
답변1
아니요, 우선 줄 바꿈이 포함된 파일 이름이 손상됩니다. 또한 필요 이상으로 복잡하고 다음과 같은 모든 위험을 안고 있습니다.ls를 구문 분석하다.
더 나은 버전은 다음과 같습니다(GNU 도구 사용).
#!/bin/ksh
for dir in /home/DABA_BACKUP/*
do
## Get the file names and sort them by their
## modification time
files=( "$dir"/* );
## Are there more than 60?
extras=$(( ${#files[@]} - 60 ))
if [ "$extras" -gt 0 ]
then
## If there are more than 60, remove the first
## files until only 60 are left. We use ls to sort
## by modification date and get the inodes only and
## pass the inodes to GNU find which deletes them
find dir1/ -maxdepth 1 \( -inum 0 $(\ls -1iqtr dir1/ | grep -o '^ *[0-9]*' |
head -n "$extras" | sed 's/^/-o -inum /;' ) \) -delete
fi
done
이는 모든 파일이 동일한 파일 시스템에 있다고 가정합니다. 그렇지 않으면 예기치 않은 결과(예: 잘못된 파일 삭제)가 발생할 수 있습니다. 동일한 inode를 가리키는 하드 링크가 여러 개 있는 경우에도 제대로 작동하지 않습니다.
답변2
#! /bin/zsh -
for dir (/home/DABA_BACKUP/*) rm -f $dir/*(Nom[61,-1])
~을 위한zsh-무지;-):
for var (list) cmd
: 루프의 짧은 버전입니다for var in list; do cmd; done
(구문을 연상시킵니다perl
).$dir
:zsh
다른 쉘처럼 변수를zsh
인용할 필요가 없습니다.분명히split
연산자 이므로glob
암시적으로 수행하지 마세요.분할+전역매개변수가 확장된 경우.*(...)
: 그리고글로벌 예선:N
:nullglob
: 불일치가 있으면 오류를 발생시키는 대신 glob이 null로 확장됩니다.m
:오생성된 파일을 다음 위치에 배치합니다.쌀수정 시간(가장 작은 것부터).[61,-1]
: 정렬된 목록의 하단에서 61번째 항목을 선택합니다.
따라서 기본적으로 60개의 가장 어린 파일을 제외한 모든 파일이 삭제됩니다.
답변3
제거할 가장 오래된 항목 목록을 얻으려면(최신 항목 60개 유지):
ls -t | tail -n +61
접근 방식의 주요 문제는 여전히 여기에서 해결해야 합니다. 만약을 대비하여 파일을 처리하는 방법(다소 복잡한 프로그램을 대체):
cd /home/DABA_BACKUP || exit 1
ls -t | tail -n +61 | xargs rm -rf
참고: 당신이 가지고 있는 것처럼 보이기 때문에일일 백업find
예를 들어, 파일 날짜의 합계를 기반으로 하는 방법을 사용할 수도 있습니다 .
find /home/DABA_BACKUP -mtime +60 -exec ls {} +
( ls
이 명령은 올바른 작동을 다시 확인한 후 적절한 명령으로 대체됩니다 rm
.)
답변4
파일 이름이 모두 backup_*이라는 것을 알고 있는 경우 해당 파일만 처리하고 실수로 디렉토리에 들어간 파일은 처리하지 않도록 해당 파일을 ls 명령에 포함해야 합니다. 그런 다음 파이프라인에서 ls를 사용하여 한 줄에 1개의 파일만 나열한 다음 개수만 계산하므로 정렬이 필요하지 않습니다.
count_files=$(ls -U backup_* | wc -l)
그리고
for part in $(ls -rt backup_*);do
rm -rf "$part"
todelete=$(($todelete-1))
if [[ $todelete -eq 0 ]]; then
break
fi
done