전체 스크립트.

전체 스크립트.

설정된 제한을 초과하면 오래된 파일을 지우려는 스크립트가 있습니다.

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

/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)가 있을 가능성이 높습니다. 이것은 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

관련 정보