Linux에서 10 개의 최신 파일을 제외한 모든 파일을 어떻게 삭제합니까?


49

로그 파일로 가득 찬 디렉토리를 관리 가능하게 유지하려고합니다. 매일 밤 가장 최근 10 개를 제외한 모든 것을 삭제하고 싶습니다. 단일 명령으로 어떻게 할 수 있습니까?


3
logrotate 살펴보기
knittl


@ michael 내 토론이 먼저 작성된 경우 어떻게 내 복제본이 될 수 있습니까?
dev4life

@ovaherenow "귀하의"? 두 질문 모두에 당신의 이름이 표시되지 않으므로 어떤 의미인지 잘 모르겠습니다. 내 의견은 어느 쪽이 다른 쪽과 중복되는지 나타내지 않습니다. 그러나 그것은 중요하지 않습니다. 단지 링크가있는 주석 일뿐입니다. 질문 또는 두 질문 모두에 추가 될 수 있습니다. 하나 또는 다른 하나를 복제본으로 표시하는 것은 다른 사람 (관리자)에게 달려 있습니다. 악의적 인 슬리 트는 의도 된 것이 아니며 어떤 것도 인식되어서는 안됩니다. 어떤 질문이 가장 먼저 였는지, 어떤 질문에 가장 적합한 답이 있는지가 더 중요합니다. 다시 링크는이 토론을 용이하게하며 답을 결정하지 않습니다.
마이클

@ 마이클 와우. 정말 이상합니다. 이 스레드는 나에 의해 열렸지만 분명히 내 사용자 이름이 아닙니다. 그러나이 스레드에 대해 알림을 받고 있습니다.
dev4life

답변:


58

이식 가능하고 안정적인 솔루션을 얻으려면 다음을 시도하십시오.

ls -1tr | head -n -10 | xargs -d '\n' rm -f --

tail -n -10다른 답변 중 하나의 구문은 (나의 RHEL5 시스템에서, 예) 모든 곳에서 작동하지 않습니다.

그리고 사용 $()또는 ``의 명령 줄에서 rm실행의 위험

  1. 공백으로 파일 이름 나누기
  2. 최대 명령 줄 문자 제한을 초과합니다.

xargs문자 제한 내에서 통과 할 수있는 인수 수를 자동으로 파악 -d '\n'하고 입력 행 경계에서만 분할 되므로이 두 가지 문제를 해결합니다 . 기술적으로 이것은 줄 바꿈이있는 파일 이름에 여전히 문제를 일으킬 수 있지만 공백이있는 파일 이름보다 훨씬 덜 일반적이며 줄 바꿈 주위의 유일한 방법은 훨씬 복잡합니다.

xargs (이전의 AIX 시스템, 아마도?)가없는 경우 루프를 만들 수 있습니다.

ls -1tr | head -n -10 | while IFS= read -r f; do
  rm -f "$f"
done

rm각 파일에 대해 별도의 파일을 생성하기 때문에 약간 느려지 지만 위의 1 및 2 경고를 피할 수는 있지만 여전히 파일 이름의 줄 바꿈이 발생합니다.


@HaukeLaging : head(1)맨 페이지에서 :-n, --lines=[-]K print the first K lines instead of the first 10; with the leading '-', print all but the last K lines of each file
Isaac Freeman

Solaris 10에서 headxargs주고 오류. 올바른 옵션은 head -n 10xargs rm -f입니다. 전체 명령은 다음과 같습니다ls -1tr ./ | head -n 10 | xargs rm -rf
DmitrySandalov

1
(가) 주 ls -1tr수 ONE하지 문자 "L"입니다.
shonky linux user

1
개행은 드물지만 ext 파일 이름에는 유효한 문자입니다. 즉, "that"및 "that \ nthing"파일이있는 경우이 스크립트가 "that \ nthing"에 도달하면 "that"을 삭제하고 "thing"을 삭제할 수 없을 때 오류가 발생하며 "that \ nthing"(의도 한 대상)은 영향을받지 않습니다.
Synthead

1
@IsaacFreeman 나쁜 조언을 삭제했습니다.
Walf

20

스크립트에 포함시키려는 코드는

 rm -f $(ls -1t /path/to/your/logs/ | tail -n +11)

-1(숫자 하나) 옵션을 인쇄 한 줄에 각 파일은 안전합니다. -f에 대한 옵션은 rm이 경우에 존재하지 않는 파일을 무시하도록 지시 ls반환 아무것도.


오리지널 포스터는 여기 이 명령을 시도했지만 작동하지 않습니다. "rm : missing operand"오류가 발생 함
user75814

2
올바른 경로를 사용 했습니까? 분명히 /path/to/your/logs올바른 경로를 입력하도록 구성되었습니다. 버그를 찾으려면 파트 ls -t /path/...ls -t /path/... | tail -n +11단독으로 실행하고 결과가 올바른지 확인하십시오.
Daniel Böhmer

1
@HaukeLaging 나는 당신이 뭔가 잘못했다고 확신합니다. 을 마음 +수 전에. 그것은하게 tail마지막 n 요소하지만, n 번째부터 시작하여 모든 요소를 인쇄 할 수 없습니다. 다시 체크인했으며 명령은 모든 상황에서 가장 최근 파일 10 개보다 오래된 요소 만 제거해야합니다.
Daniel Böhmer

@halo 참으로 죄송합니다.
Hauke ​​Laging

2
나는 당신의 대답이 매우 위험하다고 생각합니다 ls. 경로가 아닌 파일 이름을 인쇄합니다. 그래서 당신 rm -f은 현재 디렉토리에있는 파일들을 제거하려고 시도 할 것입니다
Jürgen Steinblock

14

분명히 파싱 ls은 악하다 .

각 파일이 매일 생성되고 지난 10 일 이내에 생성 된 파일을 유지하려는 경우 다음을 수행 할 수 있습니다.

find /path/to/files -mtime 10 -delete

또는 각 파일이 임의로 생성 된 경우 :

find /path/to/files -maxdepth 1 -type f -printf '%Ts\t%P\n' | sort -n | head -n -10 | cut -f 2- | xargs rm -rf

5
-mtime 10 -delete정확히 10 일 전에 수정 된 파일 만 삭제합니다. 이전 파일은 삭제되지 않습니다. -mtime +11 -delete지난 10 일 동안 로그 파일을 남기고 11 일 이상 전에 수정 된 파일을 삭제합니다.
Markus

1
파일의 전체 경로를 갖기 위해서는 %p대신 사용 %P이 필요 하다고 생각합니다 printf. 그렇지 않으면 rm -rf작동하지 않습니다.
jalopaba

9

logrotate와 같은 도구가이를 수행합니다. 로그 관리가 훨씬 쉬워집니다. 후광이 제안 될 때 추가 정리 루틴을 포함 할 수도 있습니다.



1

에서 여기 :

#! /bin/sh
# keepnewest
#
# Simple directory trimming tool to handle housekeeping
# Scans a directory and deletes all but the N newest files
#
# Usage: cleanup <dir> <number of files to keep>
#
# v 1.0 Piers Goodhew 1/mar/2007. No rights retained.


if [ $# -ne 2 ]; then
  echo 1>&2 "Usage: $0 <dir> <number of files to keep>"
  exit 1
fi

cd $1
files_in_dir=`ls | wc -l`
files_to_delete=`expr $files_in_dir - $2`
if [ $files_to_delete -gt 0 ]; then
  ls -t | tail -n $files_to_delete | xargs rm
  if [ $? -ne 0 ]; then
    echo "An error ocurred deleting the files"
    exit 1
  else
    echo "$files_to_delete file(s) deleted."
  fi
else
  echo "nothing to delete!"
fi

1
이 답변을 제공해 주셔서 감사합니다. 이와 같은 코드를 제공하면 도움이되지만 코드 사용 방법 또는 코드 기능에 대한 추가 정보를 제공하는 데 도움이됩니다. 수정 버튼을 사용하여 나중에 게시물을 개선 할 수 있습니다.
닌클

1

Bash에서는 다음을 시도 할 수 있습니다.

ls -1t | (i=0; while read f; do
  if [ $i -lt 10 ]; then
    ((i++))
    continue
  else
    rm -f "$f"
  fi
done)

가장 최근의 10 개는 나머지를 삭제합니다. logrotate가 더 나을 수 있습니다. 잘못된 쉘 관련 답변을 수정하고 싶습니다.


1

확실하지 않은 사람에게 도움이 될 것입니다. 방금 ls정렬을 수행하는 데 사용한 이상한 문자로 인한 잠재적 인 문제를 피하고 파일 inode을 삭제에 사용했습니다.

현재 디렉토리의 경우 수정 시간을 기준으로 가장 최근 10 개의 파일이 유지됩니다.

ls -1tri | awk '{print $1}' | head -n -10 | xargs -n1 -t -Iinode find . -inum inode -exec rm -i {} \;


0

busybox (router)를위한 우아한 솔루션이 필요했습니다. 모든 xargs 또는 어레이 솔루션은 나에게 쓸모가 없었습니다. find와 mtime은 우리가 10 개의 항목에 대해 이야기하고 있기 때문에 반드시 10 일이 아니라는 정답이 아닙니다. Espo의 대답은 가장 짧고 깨끗했으며 아마도 가장 보편적 인 것이 었습니다.

공백이 있거나 파일을 삭제하지 않을 때의 오류는 단순히 표준 방법으로 해결됩니다.

rm "$(ls -td *.tar | awk 'NR>7')" 2>&-

좀 더 교육적인 버전 : awk를 다르게 사용하면 모든 것을 할 수 있습니다. 일반적 으로이 방법을 사용하여 변수를 awk에서 sh로 (반환) 전달합니다. 우리가 할 수없는 모든 시간을 읽었을 때, 나는달라고 간청합니다 : 여기에 방법이 있습니다.

파일 이름의 공백과 관련하여 문제가없는 .tar 파일의 예 테스트하려면 "rm"을 "ls"로 바꾸십시오.

eval $(ls -td *.tar | awk 'NR>7 { print "rm \"" $0 "\""}')

설명:

ls -td *.tar시간별로 정렬 된 모든 .tar 파일을 나열합니다. 현재 폴더의 모든 파일에 적용하려면 "d * .tar"부분을 제거하십시오.

awk 'NR>7... 처음 7 줄을 건너 뜁니다.

print "rm \"" $0 "\"" 라인을 구성합니다 : rm "file name"

eval 그것을 실행

우리는를 사용 rm하고 있기 때문에 스크립트에서 위의 명령을 사용하지 않을 것입니다! 더 현명한 사용법은 다음과 같습니다.

(cd /FolderToDeleteWithin && eval $(ls -td *.tar | awk 'NR>7 { print "rm \"" $0 "\""}'))

ls -t명령 을 사용하는 경우 다음 touch 'foo " bar'과 같은 어리석은 예에는 아무런 영향을 미치지 않습니다 touch 'hello * world'. 우리는 그런 이름을 가진 파일을 실제로 만들지 않습니다!

각주. 이런 식으로 변수를 sh에 전달하려면 인쇄를 수정하면됩니다.

print "VarName="$1

변수 VarName를 값 으로 설정합니다 $1. 한 번에 여러 변수를 만들 수 있습니다. 이것은 VarName일반적인 sh 변수가되고 나중에 스크립트 나 쉘에서 사용될 수 있습니다. 따라서 awk로 변수를 만들고 셸에 다시 제공하려면 다음을 수행하십시오.

eval $(ls -td *.tar | awk 'NR>7 { print "VarName="$1 }'); echo "$VarName"

0

나는 ls 파싱이 악하다는 것에 동의합니다!

마지막 5 개 파일 만 /srv/backups경로에 보관하십시오 .

find /srv/backups -maxdepth 1 -type f -printf '%Ts\t%P\n' \
    | sort -rn \
    | tail -n +6 \
    | cut -f2- \
    | xargs -r r

0

Isaac Freeman 응답을 기반으로하지만 모든 디렉토리에서 작업 중 :

ls -1tr $PATH_TO_DELETE/* | head -n -10 | xargs -d '\n' rm -f --

다음과 같이 접두사를 설정할 수도 있습니다 $PATH_TO_DELETE/testFi*

당신이 사용하는 경우 *사후이 PATH ls출력됩니다 절대 파일 이름, "내"bash는 적어도 :)

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.