전체 스크립트.

전체 스크립트.

설정된 제한보다 큰 경우 오래된 파일을 정리하려는 스크립트가 있습니다.

나는 다음 명령을 가지고 있습니다 :

/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제공됩니다 . 제거될 것이기 때문에 둘 중 어느 것도 존재하지 않기를 바랍니다.rmsomedir/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

관련 정보