while 루프는 모든 파일을 삭제하고 루프에 갇히게 됩니다.

while 루프는 모든 파일을 삭제하고 루프에 갇히게 됩니다.

특정 수의 파일이 남을 때까지 파일을 삭제하기 위해 while 루프를 사용할 수 없습니다.

이것이 내가 가진 것입니다:

touch while/151234
touch while/152355
touch while/151694
touch while/153699
touch while/156946
NUMSNAPS=$(ls while | awk '{print $1}' | wc -l)
RETAIN=2

while [ "$RETAIN" -le "$NUMSNAPS" ]; do
    OLDEST=$(ls | awk '{print $1}' | head -n 1)
    rm "$OLDEST"
done

실제로 다른 타사 명령과 함께 사용되는 테스트이기 때문에 find를 사용하여 이러한 파일을 삭제할 수 없습니다. DOCTL을 사용하여 스냅샷을 찾고 하나가 남을 때까지 삭제할 계획입니다.

답변1

절대 변경하지 않는 두 개의 변수를 기반으로 특정 조건을 테스트하는 루프가 있습니다. NUMSNAPS각 반복마다 값을 1씩 감소시키는 것을 의미한다고 가정합니다 .


zsh쉘 에서는 할 수 있습니다

retain=2

rm -f while/*(DN.Om[retain+1,-1])

$retain최근 수정된 파일을 제외한 모든 일반 파일(숨겨진 이름이 있는 파일 포함)을 삭제합니다 . 수천 개의 파일이 발생하는 경우 다음을 사용할 수 있습니다 zargs.

retain=2

autoload -U zargs
zargs -- while/*(DN.Om[retain+1,-1]) -- rm

파일을 이름별로 정렬하려면 Om("Mtime 타임스탬프 기준 내림차순 정렬")을 On("이름별 내림차순 정렬")로 바꾸세요.

zsh분명히 예를 들어 사용하는 대신 다른 쉘에서 호출할 수 있습니다 .

retain=2

zsh -c 'rm -f $2/*(DN.Om[$1+1,-1])' zsh "$retain" "while"

이는 또한 인라인 스크립트에 보관할 디렉터리 이름과 파일 수를 전달하므로 기존 비스크립트에 더 쉽게 병합할 수 있습니다 zsh.


쉘 에서는 bash실제로 원하지 않습니다출력 구문 분석ls. 대신에 다음을 사용하고 싶을 수도 있습니다.

shopt -s dotglob nullglob

retain=2

set -- while/*

while [ "$#" -gt "$retain" ]; do
    rm -f "$1"
    shift
done

이는 위치 인수 목록을 while디렉터리의 파일 목록(숨겨진 이름 포함)으로 설정한 다음 retain목록에 파일만 남을 때까지 해당 목록에서 파일을 제거합니다.

이렇게 하면 어색한 파일 이름 문제를 방지하고 ls삭제된 파일마다 한 번 호출하는 것을 방지할 수 있습니다.

이 코드는 이름(마지막으로 수정된 타임스탬프 아님)을 기준으로 파일을 삭제합니다. 이것은 귀하의 코드에서도 수행하려는 작업인 것 같습니다.

답변2

그런데 왜 전체 목록을 얻을 수 없고 필요한 파일 수만 유지할 수 없습니까? 예를 들어:

ls -r while | tail -n +${retain} | xargs echo rm

답변3

스크립트를 수정하고 개선하는 방법은 다음과 같습니다.

#!/bin/bash

touch while/151234
touch while/152355
touch while/151694
touch while/153699
touch while/156946

NUMSNAPS=$(ls -1 while | wc -l)
RETAIN=2

while (( RETAIN < NUMSNAPS )); do
    OLDEST=$(ls -1t while | tail -n 1)
    rm "while/$OLDEST"
    (( --NUMSNAPS ))
done

관련 정보