설정된 제한을 초과하면 오래된 파일을 지우려는 스크립트가 있습니다.
나는 다음 명령을 가지고 있습니다 :
/bin/rm -f `/bin/ls -t $bkup_p/mysql.daily/* 2> /dev/null | /bin/awk 'NR>'5`
$bkup_p에 공백이 있을 수 있기 때문에 작동합니다.
/bin/rm -f `/bin/ls -t "$bkup_p/mysql.daily/*" 2> /dev/null | /bin/awk 'NR>'5`
그러나 이것은 작동하지 않습니다. 문제의 파일이 표시되지 않고 단지 비어 있습니다.
답변1
Bash는 수정 시간을 기준으로 파일을 필터링하고 해당 파일에 대해 명령을 실행할 때 그다지 편리하지 않습니다.
z-shell을 사용해 보는 것이 좋습니다. 먼저 를 실행한 zsh
다음
rm -i -- "$bkup_p"/mysql.daily/*(DN.Om[1,5])
이렇게 하면 특정 디렉터리에서 가장 오래된 일반 파일 5개가 삭제됩니다. 이는 여러분이 원하는 것일 수 있습니다. 분명히 이것은 필요한 경우 결국 rm -i
변경 될 것입니다 rm -f
.
5개의 최신 파일을 삭제하려면 다음을 수행하십시오.
rm -i -- "$bkup_p"/mysql.daily/*(DN.om[1,5])
자, 그것이 어떻게 작동하는지. 내부의 모든 것은 ()
기본적으로 필요에 따라 파일을 필터링하는 glob 한정자입니다.
D
도트 파일(로 시작하는 파일.
) 포함N
일치하는 항목이 없으면 오류를 보고하지 마세요..
일반 파일만 선택om
수정 시간별로 정렬(Om
역순)[1,5]
목록에서 5개의 파일만 선택하세요.
나는 이 모든 것이 파일 이름의 특수 문자(공백, 개행 문자 등)에 대해 작동해야 한다고 생각합니다.
답변2
다른 사람들이 말했듯이, ls
이 목적으로 사용해서는 안됩니다. 하지만 귀하의 환경에 더 스마트한 것이 없다면주의사항에 대해 알아보세요., 너가능한파일 이름이 다음과 같은 경우충분하다: 공백이나 인쇄할 수 없는 문자, 특히 쉘에서 와일드카드로 해석되지 않는 문자(적어도 ?*[]
)가 없습니다.
Perl과 같은 것을 사용하여 파일을 정렬하거나 파일 이름에 날짜를 넣어 전역 순서에 의존하는 것이 더 좋습니다.
즉, 두 번째 스니펫에서는 별표가 인용되어 있으므로 와일드카드가 발생하지 않습니다. 존재하지 않는 항목에 대한 오류가 표시되지만 some dir/mysql.daily/*
오류 출력을 리디렉션했기 때문에 표시되지 않습니다.
공백이 있는 파일 이름은 명령 대체의 출력이 공백을 따라 분할되어 다음과 같은 문제가 발생하므로 : 및 두 부분 some dir/foo
으로 분할됩니다 . 삭제될 것이므로 아무 것도 존재하지 않기를 바랍니다.rm
some
dir/foo
디렉터리 이름에만 공백이 포함된 경우 cd
해당 디렉터리에 먼저 들어갈 수 있습니다. 또는 IFS
기본 공백, 탭, 줄 바꿈 대신 줄 바꿈만 포함하도록 설정하세요. NAS를 언급하셨다면 비지박스(Busybox)가 있을 가능성이 높습니다. 이것은 busybox 및 bash에서 작동하며 파일 이름을 한 줄에 하나씩 인쇄합니다.
IFS=$'\n'
printf "%s\n" $( ls -t "$bkup_p/mysql.daily/"* | tail -n +6 )
제대로 작동한다고 확신하는 경우 파일을 삭제하려면 printf "%s\n"
로 바꾸세요.rm
답변3
ls
구문 분석된 출력은 새 명령으로 파이프하기 위해 출력 형식을 올바르게 지정하지 않고 이식성 문제가 있으므로 사용하지 않는 것이 좋습니다 .
나는 이런 것을 시도 할 것입니다
find $bkup_p/mysql.daily/ -type f -a -mtime +7 -a -name "*.sql" -a -exec rm -f {} +
노트:
"*.sql"
필요에 따라 이 설정을 변경하세요.-mtime +7
의미* 이 파일이 (+) 7일 전에 수정된 경우, 필요한 경우 이 파일도 변경할 수 있습니다.
무슨 일이 있어도 항상 10개의 최신 파일을 갖고 있는지 확인하고 싶다면(그리고 GNU도 가지고 있음 find
) 시도해 볼 수 있습니다.
find $bkup_p/mysql.daily/ -maxdepth 1 -type f -a -printf "%T+\t%p\n" | sort -r | sed -n '10,$p' | awk '{print $2}' | xargs rm -f
find
연산자를 사용하여 출력 형식을 지정하는 방법 에 대한 자세한 내용은 -printf
다음을 참조하세요.
man find | less '+/^\s*-printf'
답변4
작동하지 않는 문제 *
는 참조할 때 확장되지 않기 때문입니다.
다음 결과를 echo *
다음과 비교하십시오 echo "*"
.
안정적인 솔루션은 각 배열 위치에 하나의 파일이 있는 배열을 사용하는 것입니다.
운이 좋고 결과가 다음을 뒷받침한다면 -printf
:
dir="$bkup_p/mysql.daily/"
find "$dir" -printf '%T@:%i\n'
모든 파일 이름은 사용되지 않습니다. 각 파일은 한 줄입니다. 한 줄에는 숫자, 선택적 점, 콜론만 포함됩니다.
이는 쉽게 정렬할 수 있습니다.
find "$dir" -printf '%T@:%i\n' | sort -rn
가장 간단한 배열은 위치 매개변수입니다.
그러면 디렉터리의 모든 파일이 위치 인수 목록으로 설정됩니다.
set -f; set -- $(find "$dir" -printf '%T@:%i\n' | sort -n )
set -f는 와일드카드이기도 한 파일 이름 확장을 방지합니다 *
. 처음 6개의 파일 이름을 피(제거)하려면 다음을 수행하십시오 shift
.
shift 5
나머지 파일에 필요한 작업을 수행합니다.
for f
do rm -f "$(find "$dir" -inum "${f#*:}")"
done
전체 스크립트.
전체 스크립트(모든 파일 이름에 대해 강력함)는 다음과 같습니다.
dir="$bkup_p/mysql.daily/"
set -f
set -- $(find "$dir" -type f -printf '%T@:%i\n'|sort -rn)
shift 5
for f
do rm -f "$(find "$dir" -inum "${f#*:}")"
done