
설정된 제한보다 큰 경우 오래된 파일을 정리하려는 스크립트가 있습니다.
나는 다음 명령을 가지고 있습니다 :
/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와 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를 사용하면 Wilcard이기도 한 파일 이름의 확장을 방지할 수 있습니다 *
. 처음 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