[bash] bash에서 가장 최근의 X 파일을 제외한 모든 파일 삭제

bash를 사용하는 표준 UNIX 환경에서 디렉토리에서 최신 X 파일을 제외한 모든 파일을 삭제하는 명령을 실행하는 간단한 방법이 있습니까?

좀 더 구체적인 예를 제공하기 위해 매 시간마다 디렉토리에 파일 (예 : 로그 파일 또는 지워진 백업)을 기록하는 일부 cron 작업을 상상해보십시오. 5보다 작을 때까지 해당 디렉토리에서 가장 오래된 파일을 제거하는 다른 크론 작업을 실행하는 방법을 원합니다.

그리고 분명히하기 위해 파일이 하나만 존재하므로 절대 삭제해서는 안됩니다.



답변

기존 답변의 문제점 :

  • 공백이나 줄 바꿈이 포함 된 파일 이름을 처리 할 수 ​​없습니다.
    • rm인용되지 않은 명령 대체 ( rm `...`)를 직접 호출하는 솔루션의 경우 의도하지 않은 글로브가 발생할 위험이 추가됩니다.
  • 파일과 디렉토리를 구별 할 수 없음 (즉, 디렉토리가 가장 최근에 수정 된 5 개의 파일 시스템 항목 중 하나 인 경우 5 미만의 파일을 효과적으로 보유 rm하므로 디렉토리에 적용 하는 데 실패 함).

wnoise의 답변 은 이러한 문제를 해결하지만 해결책은 GNU에 따라 다릅니다 (매우 복잡합니다).

한 가지주의 사항 만 제공 되는 실용적인 POSIX 호환 솔루션 은 다음과 같습니다. 줄 바꿈 이 포함 된 파일 이름을 처리 할 수 ​​없습니다. 대부분의 사람들이 실제로 우려하는 것은 아닙니다.

기록을 위해 다음은 일반적으로 ls출력 을 구문 분석하는 것이 좋지 않은 이유에 대한 설명입니다 . http://mywiki.wooledge.org/ParsingLs

ls -tp | grep -v '/$' | tail -n +6 | xargs -I {} rm -- {}

파일 이름 마다 한 번씩 호출해야 하므로 위의 내용은 비효율적 입니다.
플랫폼 에서이 문제를 해결할 수 있습니다.xargsrm
xargs

당신이있는 경우 GNU xargs 사용 -d '\n'차종은, xargs각각의 입력 라인 별도의 인수 고려를 아직 명령 줄에 맞는 많은 인수로 전달 :

ls -tp | grep -v '/$' | tail -n +6 | xargs -d '\n' -r rm --

-r( --no-run-if-empty)는 rm입력이 없으면 호출되지 않도록합니다.

당신이있는 경우 BSD xargs (에 포함 맥 OS를 ), 당신이 사용할 수있는 -0처리 NUL로 처음 번역의 뉴 라인 후, 단락 지어진 입력 NUL( 0x0) 문자를, 또한 (일반적으로) 통과하는 모든 파일 이름. 한 번에 (것 또한 GNU와 작업 xargs) :

ls -tp | grep -v '/$' | tail -n +6 | tr '\n' '\0' | xargs -0 rm --

설명:

  • ls -tp파일 시스템 항목의 이름을 최근에 수정 한 파일 순서대로 내림차순 (가장 최근에 수정 한 항목) ( -t)으로 인쇄하고, 디렉토리를 후행 /으로 인쇄하여 ( -p) 로 표시합니다 .
  • grep -v '/$'그런 다음 -v후행 /( /$) 이있는 ( ) 행을 생략하여 결과 목록에서 디렉토리를 제거합니다 .
    • 주의 사항 : 디렉토리를 가리키는 심볼릭 링크 는 기술적으로 그 자체가 디렉토리가 아니므 로 이러한 심볼릭 링크는 제외 되지 않습니다 .
  • tail -n +6처음 건너 뜁니다 (5 개) 모두를 반환 효과, 목록의 항목 5 개 가장 최근에 수정 된 파일 (있는 경우). 파일
    을 제외 시키 려면로 전달되어야합니다 .NN+1tail -n +
  • xargs -I {} rm -- {}(그리고 그 변형) rm모든 파일 을 불러 옵니다; 일치 xargs하는 항목이 없으면 아무 것도하지 않습니다.
    • xargs -I {} rm -- {}{}각 입력 줄 을 전체로 나타내는 자리 표시자를 정의 하므로 rm각 입력 줄마다 한 번 호출되지만 포함 된 공백이있는 파일 이름을 사용하여 올바르게 처리됩니다.
    • --모든 경우에 시작하는 모든 파일 이름이 옵션 으로 -오인되지 않도록 합니다 .rm

일치하는 파일을 개별적 으로 처리 하거나 셸 배열로 수집 해야하는 경우 원래 문제 의 변형 :

# One by one, in a shell loop (POSIX-compliant):
ls -tp | grep -v '/$' | tail -n +6 | while IFS= read -r f; do echo "$f"; done

# One by one, but using a Bash process substitution (<(...), 
# so that the variables inside the `while` loop remain in scope:
while IFS= read -r f; do echo "$f"; done < <(ls -tp | grep -v '/$' | tail -n +6)

# Collecting the matches in a Bash *array*:
IFS=$'\n' read -d '' -ra files  < <(ls -tp | grep -v '/$' | tail -n +6)
printf '%s\n' "${files[@]}" # print array elements


답변

디렉토리에서 가장 최근 파일 5 개 (또는 숫자)를 제외한 모든 파일을 제거하십시오.

rm `ls -t | awk 'NR>5'`


답변

(ls -t|head -n 5;ls)|sort|uniq -u|xargs rm

이 버전은 공백이있는 이름을 지원합니다.

(ls -t|head -n 5;ls)|sort|uniq -u|sed -e 's,.*,"&",g'|xargs rm


답변

thelsdj의 답변의 간단한 변형 :

ls -tr | head -n -5 | xargs --no-run-if-empty rm 

ls -tr은 가장 오래된 것부터 모든 파일을 표시합니다 (-t newest, -r reverse).

head -n -5는 5 개의 마지막 행을 제외한 모든 행을 표시합니다 (예 : 5 개의 최신 파일).

xargs rm은 선택된 각 파일에 대해 rm을 호출합니다.


답변

find . -maxdepth 1 -type f -printf '%T@ %p\0' | sort -r -z -n | awk 'BEGIN { RS="\0"; ORS="\0"; FS="" } NR > 5 { sub("^[0-9]*(.[0-9]*)? ", ""); print }' | xargs -0 rm -f

GNU print -printf, GNU sort -z, GNU awk “\ 0”, GNU xargs -0에는 필요하지만 개행이나 공백이있는 파일을 처리합니다.


답변

현재 디렉토리에 디렉토리가 있으면 이러한 모든 대답이 실패합니다. 다음은 작동하는 것입니다.

find . -maxdepth 1 -type f | xargs -x ls -t | awk 'NR>5' | xargs -L1 rm

이:

  1. 현재 디렉토리에 디렉토리가있을 때 작동

  2. 이전 파일을 제거 할 수 없더라도 (권한 등으로 인해) 각 파일을 제거하려고합니다.

  3. 현재 디렉토리의 파일 수가 과도하고 xargs일반적으로 ( -x)

  4. 파일 이름에 공백을 넣지 않습니다 (아마도 잘못된 OS를 사용하고 있습니까?)


답변

ls -tQ | tail -n+4 | xargs rm

각 파일 이름을 인용하여 수정 시간별로 파일 이름을 나열하십시오. 처음 3 개 (가장 최근 3 개)를 제외합니다. 남은 것을 제거하십시오.

mklement0의 유용한 의견 후 편집 (감사합니다!) : -n + 3 인수를 수정했으며 파일 이름에 줄 바꿈이 있거나 디렉토리에 하위 디렉토리가 있으면 예상대로 작동하지 않습니다.